我只是想学习新的c ++ 17更改“直接列表初始化的自动规则”
很少有stackoverflow问题线程有答案,比如它不安全 Why is direct-list-initialization with auto considered bad or not preferred?
尝试了一个选定的答案以理解
#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';
}
但令我惊讶的是它编译时没有任何警告或编译错误 输出
a 3Foo
b 3Foo
Program ended with exit code: 0
这是否意味着现在使用auto进行直接初始化是安全的
例如像这样
auto x { 1 };
答案 0 :(得分:6)
&#34;安全&#34;是在旁观者的眼中。
C ++ 14的行为是安全的&#34;,因为它定义了结果。 auto var_name{expr}
会创建一个元素的initializer_list
。
C ++ 17使得auto var_name{expr}
导致与auto var_name = expr;
相同的类型推导。只要您预计会出现这种情况,那么它就是安全的&#34;。但它已经不再安全了#34;比旧的行为。
然后,这是一种向后与C ++ 14行为不兼容的语言变化。按照这个标准,它并不安全&#34;,因为C ++ 14用户期望你的代码做的事情与C ++ 17编译器不同。所以它会产生一些微妙的混乱,这可能不安全。
然后出现了#34;统一初始化&#34;应该是&#34;制服&#34; (即:在所有地方的相同规则下执行相同类型的初始化),但auto var_name{expr}
将执行与auto var_name = {expr}
非常不同的操作。后者仍然是initializer_list
;前者将是复制/移动。通过这个标记,它不安全&#34;假设&#34;统一初始化&#34;是统一的。
然后,C ++ 17的行为有时候是你真正想要的。将变量从单个值初始化为您,意味着复制/移动它。毕竟,如果你已经完成decltype(expr) var_name{expr}
,那就是你得到的行为。所以从这个角度来看,它似乎是安全的#34;行为。
至少,我们可以说通过两条规则可以更好地教育这种情况:
auto
变量的直接列表初始化意味着&#34;将表达式复制/移动到变量中,如果您提供多个表达式,则表示您使用了错误的语法。&# 34; auto
变量的复制列表初始化意味着&#34;制作initializer_list
,如果您提供无法执行此操作的值,则表明您使用了错误语法&#34; 也许简单性会产生一种“安全感”。
启动这些更改的 The document通过坚持上述规则返回堆叠绑定initializer_list
,从而减少了意外UB的可能性。这是&#34; safe&#34;。
所以这一切都取决于你的意思&#34;安全&#34;。