我读到在C ++ 17中我们可以在这样的if
语句中初始化变量
if (int length = 2; length == 2)
//execute something
代替
int length = 2;
if (length == 2)
//do something
即使它更短,它也会影响代码的可读性(特别是对于不了解此新功能的人而言),我认为这对于大型软件开发而言是一种不良的编码实践。
除了使代码更短之外,使用此功能还有什么好处?
我读到在C ++ 17中我们可以在这样的if
语句中初始化变量
if (int length = 2; length == 2)
//execute something
代替
int length = 2;
if (length == 2)
//do something
即使它更短,它也会影响代码的可读性(特别是对于不了解此新功能的人而言),我认为这对于大型软件开发而言是一种不良的编码实践。
除了使代码更短之外,使用此功能还有什么好处?
if (int length = 2; length == 2)
也许您第一次看到它是令人惊讶的,但这并不复杂,一个人无法理解,因此已经第二次了,这将不再是一个大惊喜,并且在它属于的范围内声明是促成可读性的主要因素之一。恕我直言,你的前提是错误的;)
Answers:
它的范围仅限length
于if
一个。因此,您将获得我们被允许写作时最初获得的收益
for(int i = 0; i < ... ; ++i) {
// ...
}
而不是变量泄漏
int i;
for(i = 0; i < ... ; ++i) {
// ...
}
短寿命变量会更好,原因有几个。但仅举几例:
寿命越短,阅读无关的代码行时需要记住的内容就越少。如果i
在循环或if
语句之外不存在,那么我们不需要在它们之外关注它的值。我们也不必担心其值会与程序超出其预期范围的其他部分交互(如果i
在另一个循环中重用以上内容,则可能会发生这种情况)。它使代码更易于遵循和推理。
如果变量拥有资源,那么该资源现在将保持最短的时间。而且这没有多余的花括号。还明确了资源与if
单独资源有关。将此视为激励性的例子
if(std::lock_guard _(mtx); guarded_thing.is_ready()) {
}
如果您的同事不知道该功能,请教他们!不想学习的快乐程序员是避免使用功能的不好借口。
if (auto p = ptr.lock(); p && p->foo()) bar(*p);
{int i = 2; if (i == 2) {...}}
”(请注意其他范围。)
除了使代码更短之外,使用此功能还有什么好处?
您减少了可变范围。这确实有意义并提高了可读性,因为它增强了您需要推理的标识符的位置。我同意if
应该避免在语句内部使用长init语句,但是对于简短内容而言,这很好。
请注意,您已经可以在C ++ 17之前的版本中对结果进行初始化和分支:
int *get(); // returns nullptr under some condition
if (int *ptr = get())
doStuff();
这取决于个人的看法,但是您可以考虑更明确地理解明确的条件:
if (int *ptr = get(); ptr != nullptr)
doStuff();
此外,通过提及人们不习惯的事实来反对功能的可读性是危险的。人们在某个时候还不习惯使用智能指针,但是今天我们仍然都同意(我想)他们在那里是一件好事。
if (auto p =get ())
因为已定义了运算符bool
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
子句。以前这是不可能的。但是现在我们可以做:
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
您可以增加表现力。
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
都是有效的,要容易得多。
但是,如果我们谈论的是无法转化为bool
那样的东西怎么办?
if (auto itr = find(bob)) {
}
那不行 但是有了这个新功能,我们可以:
if (auto itr = find(bob); itr != end()) {
}
添加一个子句“此初始化何时有效”。
从本质上讲,这给了我们一组令牌,这些令牌的意思是“初始化某些表达式,当它有效时,执行一些代码。当它无效时,将其丢弃”。
从C ++ 98开始,进行指针测试技巧已经很普遍了。一旦您接受了这一点,这种扩展就是自然的。