我读到在 C + + 17中,我们可以像这样在 if语句中初始化变量
if
if (int length = 2; length == 2) //execute something
而不是
int length = 2; if (length == 2) //do something
即使它更短,它也会影响代码的可读性(特别是对于不知道这个新特性的人来说) ,我认为这对于大型软件开发来说是一种糟糕的编码实践。
除了使代码更短之外,使用这个特性还有什么好处吗?
你减少了可变范围。这确实有意义,并且增加了可读性,因为它加强了您需要推理的标识符的位置。我同意应该避免使用 if语句中的 long init 语句,但是对于短语句,这样做没有问题。
注意,您已经可以在 pre-C + + 17中对结果进行初始化和分支了:
int *get(); // returns nullptr under some condition if (int *ptr = get()) doStuff();
这取决于一个人的个人观点,但你可以考虑一个更易读的明确条件:
if (int *ptr = get(); ptr != nullptr) doStuff();
此外,通过提及人们不习惯某个特性的事实来反对它的可读性是危险的。人们在某些时候并不习惯聪明的指针,但是我们今天仍然同意(我想)他们在那里是一件好事。
它将 length的范围限制为仅 if。所以你得到了和我们最初被允许写作时一样的好处
length
for(int i = 0; i < ... ; ++i) { // ... }
而不是变量泄漏
int i; for(i = 0; i < ... ; ++i) { // ... }
有几个原因可以说明短期变量是更好的选择,但是举几个例子:
某些东西存在的时间越短,在阅读不相关的代码行时需要记住的东西就越少。如果 i不存在于循环或 if语句之外,那么我们就不需要考虑它在循环或 if语句之外的值。我们也不需要担心它的值会与程序中超出其预期作用域的其他部分交互(如果上面的 i在另一个循环中被重用,可能会发生这种情况)。它使代码更容易跟踪和推理。
i
如果变量持有一个资源,那么该资源现在被持有的时间尽可能短。没有多余的花括号。它也清楚地表明了资源只与 if有关。把这当作一个激励人心的例子
if(std::lock_guard _(mtx); guarded_thing.is_ready()) { }
If your colleagues aren't aware of the feature, teach them! Appeasing programmers who don't wish to learn is a poor excuse to avoid features.
If 语句的新形式有许多用途。
当前,初始值设定项要么在语句之前声明,要么在 泄漏到环境范围中,或者使用显式范围 新的形式,这样的代码可以写得更紧凑,并改进 作用域控制使一些以前容易出错的结构有点 更有活力。
使用初始值设定项打开 If 语句的标准建议
因此,总的来说,此语句简化了常见的代码模式,并帮助用户紧密控制范围。
希望能有所帮助!
为了最小化变量的范围,有一个习惯用法,它只定义在创建时有效的资源(例如 文件流对象) :
if(auto file = std::ifstream("filename")) { // use file here } else { // complain about errors here } // The identifier `file` does not pollute the wider scope
有时,您希望能够逆转该测试的逻辑,使失败成为主子句,而有效资源成为 else子句。这在以前是不可能的。但现在我们可以做的是:
else
if(auto file = std::ifstream("filename"); !file) { // complain about errors here } else { // use file here }
例如抛出一个异常:
if(auto file = std::ifstream(filename); !file) throw std::runtime_error(std::strerror(errno)); else { // use file here }
有些人喜欢编写代码,这样一个函数就会 提前放弃出错,否则就会进步。这个成语把中止逻辑放在一些人可能觉得更自然的延续逻辑之上。
它对逻辑事件特别有用:
char op = '-'; if (op != '-' && op != '+' && op != '*' && op != '/') { std::cerr << "bad stuff\n"; }
看起来有点粗糙。除非您非常熟悉 OR, AND的否定式,否则您可能需要停下来思考一下这个逻辑——这通常是糟糕的设计。使用 if-initialization可以增加表现力。
OR, AND
if-initialization
char op = '-'; if (bool op_valid = (op == '-') || (op == '+') || (op == '*') || (op == '/'); !op_valid) { std::cerr << "bad stuff\n"; }
命名的变量也可以在 if中重用,例如:
if (double distance = std::sqrt(a * a + b * b); distance < 0.5){ std::cerr << distance << " is too small\n"; }
这是伟大的,特别是考虑到变量的作用域,因此不会污染后来的空间。
这是现有特性的一个扩展,以我的经验来看,它有助于提高可读性。
if (auto* ptr = get_something()) { }
在这里,我们都创建变量 ptr,并测试它是否为非空。ptr的范围仅限于其有效的地方。说服自己 ptr的所有使用都是有效的要容易得多。
ptr
但是,如果我们讨论的是一些不能以这种方式转换为 bool的东西呢?
bool
if (auto itr = find(bob)) { }
这不起作用,但有了这个新功能,我们可以:
if (auto itr = find(bob); itr != end()) { }
添加一个子句,说明“此初始化何时有效”。
实际上,这给了我们一组标记,意思是“初始化一些表达式,当它有效时,执行一些代码。当它无效时,丢弃它。”
自从 C + + 98以来,使用指针测试技巧已经成为惯例。