Initializing variables in an "if" statement

Arn*_*rne 78 c++ c++17

I read that in C++17 we can initialize variables in if statements like this

if (int length = 2; length == 2)
    //execute something
Run Code Online (Sandbox Code Playgroud)

Instead of

int length = 2;
if (length == 2)
    //do something
Run Code Online (Sandbox Code Playgroud)

Even though it is shorter, it affects the code readability (especially for people who don't know this new feature), which I suppose is a bad coding practice for large software development.

除了使代码更短之外,使用此功能还有什么好处?

Sto*_*ica 97

它的范围仅限lengthif一个。因此,您将获得我们被允许写作时最初获得的收益

for(int i = 0; i < ... ; ++i) {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

而不是变量泄漏

int i;
for(i = 0; i < ... ; ++i) {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

短寿命变量会更好,原因有几个。但仅举几例:

  1. 寿命越短,阅读无关的代码行时需要记住的内容就越少。如果i在循环或if语句之外不存在,那么我们不需要在它们之外关注它的值。我们也不必担心其值会与程序的预期范围之外的其他部分交互(如果i在另一个循环中重用以上内容,则可能会发生这种情况)。它使代码更易于遵循和推理。

  2. 如果变量拥有资源,那么该资源现在将保持最短的时间。而且这没有多余的花括号。还明确了资源与if单独资源有关。将此视为激励性的例子

    if(std::lock_guard _(mtx); guarded_thing.is_ready()) {
    }
    
    Run Code Online (Sandbox Code Playgroud)

如果您的同事不知道该功能,请教他们!不想学习的快乐程序员是避免使用功能的不佳借口。

  • 我要抓住最后一句话,然后将其拍在两米长的海报上。 (12认同)
  • 同样,短暂的(范围狭窄的)变量应该减少错误,因为一旦达到目的,您就不会在以后的代码中意外地重用该变量。 (3认同)
  • 或者使用弱指针:`if (auto p = ptr.lock(); p &amp;&amp; p-&gt;foo()) bar(*p);` (2认同)

lub*_*bgr 23

除了使代码更短之外,使用此功能还有什么好处?

您减少了可变范围。这确实有意义并提高了可读性,因为它增强了您需要推理的标识符的位置。我同意if应该避免在语句内部使用长init语句,但是对于简短内容来说,这很好。

请注意,您已经可以在C ++ 17之前的版本中对结果进行初始化和分支:

int *get(); // returns nullptr under some condition

if (int *ptr = get())
    doStuff();
Run Code Online (Sandbox Code Playgroud)

这取决于个人的意见,但是您可以考虑将明确的条件更容易理解:

if (int *ptr = get(); ptr != nullptr)
    doStuff();
Run Code Online (Sandbox Code Playgroud)

此外,通过提及人们不习惯的事实来争论功能的可读性是危险的。人们在某个时候还不习惯使用智能指针,但是今天我们仍然都同意(我想)他们在那里是一件好事。

  • 您可以使用`if(auto p = get())`,因为定义了操作符bool (4认同)

小智 19

if语句的新形式有很多用途。

当前,初始化程序要么在语句之前声明,然后泄漏到环境范围中,要么使用显式范围。使用新格式,可以更紧凑地编写此类代码,并且改进的范围控制使一些以前容易出错的构造更加健壮。

使用初始化程序为If语句打开标准提案

在此处输入图片说明

因此,总而言之,该语句简化了常见的代码模式,并帮助用户保持范围狭窄。

希望对您有所帮助!


Gal*_*lik 10

为了最小化变量的范围,有一个习惯用法定义了一个仅在创建时有效的资源(例如文件流对象):

if(auto file = std::ifstream("filename"))
{
    // use file here
}
else
{
    // complain about errors here
}

// The identifier `file` does not pollute the wider scope
Run Code Online (Sandbox Code Playgroud)

有时您希望能够颠倒该测试的逻辑,以使失败成为主要子句,而使有效资源成为该else子句。以前这是不可能的。但是现在我们可以做:

if(auto file = std::ifstream("filename"); !file)
{
    // complain about errors here
}
else
{
    // use file here
}
Run Code Online (Sandbox Code Playgroud)

一个示例可能会引发异常:

if(auto file = std::ifstream(filename); !file)
    throw std::runtime_error(std::strerror(errno));
else
{
    // use file here
}
Run Code Online (Sandbox Code Playgroud)

有些人喜欢编码,以便函数可以在出现错误时提早中止,否则将继续执行。这种习惯用法使中止逻辑在物理上处于某些人可能会觉得更自然的延续逻辑之上。


Sta*_*nny 8

它对于逻辑事件特别有用。考虑以下示例:

char op = '-';
if (op != '-' && op != '+' && op != '*' && op != '/') {
    std::cerr << "bad stuff\n";
}
Run Code Online (Sandbox Code Playgroud)

似乎有点粗糙。除非您对OR, AND取反非常熟悉,否则您可能需要停下来思考一下这种逻辑-通常这是较差的设计。使用,if-initialization您可以增加表现力。

char op = '-';
if (bool op_valid = (op == '-') || (op == '+') || (op == '*') || (op == '/'); !op_valid) {
    std::cerr << "bad stuff\n";
} 
Run Code Online (Sandbox Code Playgroud)

命名变量也可以在内部重复使用if。例如:

if (double distance = std::sqrt(a * a + b * b); distance < 0.5){
    std::cerr << distance << " is too small\n";
}
Run Code Online (Sandbox Code Playgroud)

这很好,特别是考虑到变量是作用域的,因此以后不会污染空间。

  • 我意识到这是主观的,但是与使用if-initializer的版本相比,我强烈希望您的“粗糙”版本。我发现它更容易阅读和理解。 (2认同)

Yak*_*ont 7

这是现有功能的扩展,有助于提高我的经验的可读性。

if (auto* ptr = get_something()) {
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们都创建了变量,ptr并测试了它是否为非空值。的范围ptr仅限于有效范围。要说服自己所有使用ptr都是有效的,要容易得多。

但是,如果我们谈论的是无法转化为bool那样的东西怎么办?

if (auto itr = find(bob)) {
}
Run Code Online (Sandbox Code Playgroud)

那不行 但是有了这个新功能,我们可以:

if (auto itr = find(bob); itr != end()) {
}
Run Code Online (Sandbox Code Playgroud)

添加一个子句“此初始化何时有效”。

从本质上讲,这给了我们一组令牌,这些令牌的意思是“初始化某个表达式,当它有效时,执行一些代码。当它无效时,将其丢弃”。

从C ++ 98开始,进行指针测试技巧已经很普遍了。一旦您接受了这一点,这种扩展就是自然的。