直接列表初始化的自动规则

Har*_*ngh 0 c++ c++17

我只是想学习新的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)

Nic*_*las 6

"安全"是旁观者的眼睛.

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},那就是你得到的行为.因此,从这个角度来看,它似乎是"安全"行为.

至少,我们可以说通过两个规则可以更好地教育这种情况:

  1. auto变量的直接列表初始化意味着"将表达式复制/移动到变量中,如果提供多个​​表达式,则表示使用了错误的语法."
  2. auto变量的复制列表初始化意味着"制作一个initializer_list,如果你提供不能做到这一点的值,你就会使用错误的语法."

也许简约创造了一种"安全感".

启动这些更改的文档表明,initializer_list通过坚持上述规则返回堆栈限制,您不太可能获得意外的UB .这是"安全"的一个定义.

所以这一切都取决于你所说的"安全".