c++ - 为什么带大括号的复制初始化会省略复制/移动构造?

标签 c++ initialization c++14 language-lawyer copy-elision

这个问题在这里已经有了答案:





Does copy list initialization invoke copy ctor conceptually?

(1 个回答)


去年关闭。




这是一个用于比较的 C++ 14 程序 direct initialisation (没有 =)与 copy initialisation ( = ):*

#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
}
使用 copy elision 编译程序禁用并运行它:
$ clang++ -std=c++14 -fno-elide-constructors main.cpp && ./a.out
产生以下输出:
A(int)
A(int)
A(int)
A(A&&)
A(int)
A(A&&)
A(int)
为什么用大括号( A e = {1}; )复制初始化会省略复制/移动构造(即使禁用复制省略)?

* 这种比较背后的动机是为了了解自 C++ 11 以来函数返回语句 (return expression) 的工作原理。当按值返回时,可以使用函数返回值的直接初始化或复制初始化。后者比像这里这样的变量的复制初始化更复杂,因为从 expression 表示的对象初始化函数返回值。涉及 trying to call the move constructor of the function return type first (即使 expression 是左值)在回退到其复制构造函数之前。并且从 C++ 17 开始,如果 expression,则保证会省略该复制/移动构造。是一个纯右值(强制 return value optimisation),而如果 expression 可能会被省略是一个泛左值(可选 named return value optimisation )。

最佳答案

copy initialisation with braces



哪有这回事。如果您使用花括号初始化列表来初始化一个对象,您正在执行某种形式的列表初始化。这有两种形式:复制列表初始化和直接列表初始化。在 C++14 中,这些与复制初始化和直接初始化无关(从技术上讲,直接列表初始化是 grammatical form of direct-initialization,但由于 list-initialization bypasses everything that direct-initialization would have done,更容易说直接列表初始化是它的自己的野兽)。

列表初始化作为一个概念初始化一个对象。使用 Typename t{}是直接列表初始化,而 Typename t = {}是复制列表初始化。但无论涉及哪种形式,都不会创建临时;列表初始化初始化有问题的对象。您的示例中唯一的对象是 e ,所以这是被初始化的对象。

符合C++14 rules for list-initialization , ecalling a constructor 初始化,传递一个值 1 ,这是花括号初始化列表中的唯一值。

关于c++ - 为什么带大括号的复制初始化会省略复制/移动构造?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61330444/

相关文章:

c++ - Basler Pylon 4 SDK 和 OPENCV 2.4.8,Linux 简单查看器

c# - C# 回调函数不是从 C++ 代码调用的

list - 附加到链表

c++ - 如何避免与 `asio::ip::tcp::iostream` 的数据竞争?

c++ - 为两个模板 : template<. ..> A = template<...> B 重载模板 operator= ,反之亦然

c++ - COM IContextMenu::InvokeCommand - 匹配 LPCMINVOKECOMMANDINFO::lpVerb 到项目

c++ - 为什么将对象作为值传递会导致 malloc : *** error for object 0x100604c50: pointer being freed was not allocated

ios - 初始化 UIView 时避免 (void)drawRect

c++ - 仅初始化结构或数组的前 n 个成员

c++ - 如何在 C++14 中将多字节值写入共享内存?