Mag*_*ero 4 c++ initialization language-lawyer copy-elision c++14
这是一个 C++ 14 程序,用于比较直接初始化(no =)和复制初始化(=):*
#include <iostream>
struct A {
A(int) { std::cout << "A(int)" << std::endl; }
A(A&) { std::cout << "A(A&)" << std::endl; }
A(A&&) { std::cout << "A(A&&)" << std::endl; }
};
int main() {
A a(1); // direct initialisation
A b{1}; // direct initialisation
A c = 1; // copy initialisation
A d = (1); // copy initialisation
A e = {1}; // copy initialisation
}
Run Code Online (Sandbox Code Playgroud)
编译程序与复制省略禁用并运行它:
$ clang++ -std=c++14 -fno-elide-constructors main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
A(int)
A(int)
A(int)
A(A&&)
A(int)
A(A&&)
A(int)
Run Code Online (Sandbox Code Playgroud)
为什么带大括号 ( A e = {1};) 的复制初始化会省略复制/移动构造(即使禁用复制省略)?
* 这种比较背后的动机是为了了解return expression自 C++ 11 以来函数返回语句 ( ) 的工作原理。当按值返回时,可以使用函数返回值的直接初始化或复制初始化。后者比像这里这样的变量的复制初始化更复杂,因为初始化由 表示的对象的函数返回值expression涉及首先尝试调用函数返回类型的移动构造函数(即使expression是左值),然后再回到它的复制构造函数。而且,由于C ++ 17,即复制/移动建设是保证,如果被省略的expression是prvalue(强制返回值优化),而它可能如果被省略expression是一个泛左值(可选的命名返回值优化)。
用大括号复制初始化
哪有这回事。如果您使用花括号初始化列表来初始化一个对象,您正在执行某种形式的列表初始化。这有两种形式:复制列表初始化和直接列表初始化。在 C++14 中,这些与复制初始化和直接初始化无关(从技术上讲,直接列表初始化是直接初始化的一种语法形式,但由于列表初始化绕过了直接初始化所做的一切,更容易说直接列表初始化是它自己的野兽)。
列表初始化作为一个概念初始化一个对象。使用的Typename t{}是直接列表初始化,而使用的Typename t = {}是复制列表初始化。但无论涉及哪种形式,都不会创建临时;列表初始化初始化有问题的对象。您的示例中唯一的对象是e,因此这是被初始化的对象。
根据C++14 的列表初始化规则,e通过调用构造函数来初始化,传递给它的值1是花括号初始化列表中的唯一值。