我只是想学习新的c ++ 17更改相关的"直接列表初始化的自动规则"
很少有stackoverflow问题线程有答案,如不安全的事情 为什么直接列表初始化与自动被认为是坏或不首选?
尝试了一个选定的答案来理解
#include <typeinfo>
#include <iostream>
struct Foo{};
void eatFoo (const Foo& f){}
int main() {
Foo a;
auto b{a};
eatFoo(b);
std::cout << "a " << typeid(a).name() << '\n';
std::cout << "b " << typeid(b).name() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
但令我惊讶的是它编译时没有任何警告或编译错误输出
a 3Foo
b 3Foo
Program ended with exit code: 0
Run Code Online (Sandbox Code Playgroud)
这是否意味着现在使用auto进行直接初始化是安全的
比如这样
auto x { 1 };
Run Code Online (Sandbox Code Playgroud)
"安全"是旁观者的眼睛.
C++ 14的行为是"安全的",因为它很好地定义了结果.auto var_name{expr}会创造initializer_list一个元素.
C++ 17使得它可以auto var_name{expr}产生与auto var_name = expr;本来相同的类型推导.只要你期望这样,那就是"安全".但它并不比旧行为更"安全".
然后,这是一种与C++ 14行为向后兼容的语言更改.按照这个标准,它不是"安全的",因为C++ 14用户希望你的代码能够做一些与C++ 17编译器不同的代码.因此它会产生一些微妙的混淆,这可能并不安全.
然后就是"统一初始化"应该是"统一"的问题(即:在所有地方在相同的规则下执行相同类型的初始化),但是auto var_name{expr}会做一些非常不同的事情auto var_name = {expr}.后者仍然是一个initializer_list; 前者将是复制/移动.通过该标记,假设"统一初始化"是均匀的并不是"安全的".
然后,C++ 17的行为有时候是你真正想要的.将变量从单个值初始化为您,意味着复制/移动它.毕竟,如果你做了decltype(expr) var_name{expr},那就是你得到的行为.因此,从这个角度来看,它似乎是"安全"行为.
至少,我们可以说通过两个规则可以更好地教育这种情况:
auto变量的直接列表初始化意味着"将表达式复制/移动到变量中,如果提供多个表达式,则表示使用了错误的语法."auto变量的复制列表初始化意味着"制作一个initializer_list,如果你提供不能做到这一点的值,你就会使用错误的语法."也许简约创造了一种"安全感".
启动这些更改的文档表明,initializer_list通过坚持上述规则返回堆栈限制,您不太可能获得意外的UB .这是"安全"的一个定义.
所以这一切都取决于你所说的"安全".