c++ - 为什么复制和 move 构造函数一起调用?

标签 c++ c++11 copy-constructor move-semantics move-constructor

考虑以下代码:

#include <iostream>
#include <vector>
using namespace std;

class A
{
public:
     A(int) { cout << "int" << endl; }
     A(A&&) { cout << "move" << endl; }
     A(const A&) { cout << "copy" << endl; }
};

int main()
{
    vector<A> v
    {
        A(10), A(20), A(30)
    };

    _getch();
    return 0;
}

输出是:

int
int
int
copy
copy
copy

A(10)A(20)A(30) 是临时的,对吧?

那么为什么要调用复制构造函数呢?不应该调用 move 构造函数吗?

通过 move(A(10)), move(A(20)), move(A(30)) 代替,输出是:

int
move
int
move
int
move
copy
copy
copy

在这种情况下,复制或 move 构造函数被调用。

发生了什么事?

最佳答案

std::vector可以从 std::initializer_list 构造,并且您正在调用该构造函数。 initializer_list 构造的规则表明此构造函数是积极首选的:

A constructor is an initializer-list constructor if its first parameter is of type std::initializer_list<E> or reference to possibly cv-qualified std::initializer_list<E> for some type E, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [ Note: Initializer-list constructors are favored over other constructors in list-initialization <...>]

另外,由于 initializer_list 的实现有点奇怪。作为在后台分配的数组,std::initializer_list<E> 对应数组的元素引用被强制复制初始化(可以省略):

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated an array of N elements of type E, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E> object is constructed to refer to that array

(以上两个引用都来自 N3337 [dcl.init.list])

但是,在您的第一个示例中,尽管名称为 ([dcl.init]/14),但拷贝可以/被省略,因此您看不到额外的拷贝结构(它们也可以 move ) 你可以感谢你的编译器,因为在 C++11 中不需要复制省略(尽管它在 C++17 中)。

参见 [class.copy] 了解更多详情(“当满足某些条件时,允许实现省略类的复制/move 构造 对象...")。

最后一部分是关键:

[support.initlist] 声明

An object of type initializer_list<E> provides access to an array of objects of type const E.

这意味着 std::vector不能直接接管内存;它必须被复制,这是您最终看到复制结构被调用的地方。

在第二个示例中,正如 Kerrek SB 所说,您阻止了我之前提到的复制省略,并导致了额外的 move 开销。

关于c++ - 为什么复制和 move 构造函数一起调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45880152/

相关文章:

c++ - 等同于memcpy不同的结果?

c++ - 为什么打印 char* 给出的是字符串而不是地址?

c++ - 使用一个 '\n' 打印

c++ - std::unique_ptr::get() 的奇怪返回行为

c++11 - boost::variant 和 operator<< 重载

c++ - 了解此 `const&` 特化的必要性

c++ - 带引用计数的复制构造函数

c++ - 通用项目的 Qt Creator c++11 语法突出显示

c++ - 为什么 getpass() 被认为是过时的功能?

c++ - 制作一个 const unique_ptr 然后尝试从它 std::move 给出相同的错误,就好像您试图访问复制构造函数一样