2017-08-25 106 views
21

考虑下面的代码:为什么复制和移动构造函数一起调用?

#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(A(10))move(A(20))move(A(30))代替,输出为:

int 
move 
int 
move 
int 
move 
copy 
copy 
copy 

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

发生了什么事?

+7

你不能从'initializer_list'元素移动。第二个示例中的附加“移动”禁止复制,因此您可以在复制之上获得额外的移动。 –

+1

好问题;答案埋在这里:http://en.cppreference.com/w/cpp/language/list_initialization – Bathsheba

+1

在一个构造函数中,需要'std :: vector'中的'std :: initializer_list',那些元素不再是右值。 –

回答

14

std::vector可以从std::initializer_list构建,并且您正在调用该构造函数。对于initializer_list施工状态的规则,此构造被积极地优选的:

构造函数是一个初始化列表构造如果它的第一个参数的类型是std::initializer_list<E> 或参照可能CV-合格std::initializer_list<E>的某种类型E ,并且有 没有其他参数,否则所有其他参数都有默认参数(8.3.6)。 [注:初始化程序列表 构造函数是优于其他构造函数列表初始化< ...>]

而且,因为那种怪异的执行的initializer_list作为引擎盖下分配的数组,元素相应的数组,该std::initializer_list<E>是指被强制为复制初始化(其可被省略):

std::initializer_list<E>类型的对象是从初始化列表构造为如果实现 分配N元件的阵列类型为E,其中N是初始化程序列表中的元素数。 该数组的每个元素是复制初始化为初始化列表的相应元素,并且所述 对象std::initializer_list<E>被构造为指的是阵列

(这两篇文献以上从N3337 [dcl.init.list] )

然而,在你的第一个例子中,可以拷贝/是省略掉尽管名称([dcl.init]/14),所以你看不到一个额外的拷贝构造(它们也可以移动),您可以感谢你的编译器,因为copy elision在C++ 11中不是必需的(尽管它在C++ 17中)。

有关更多详细信息,请参见[class.copy](“符合某些条件时,允许实现省略类 object的复制/移动构造...”)。

最后一部分是关键:

[support.initlist]指出

initializer_list<E>类型的对象提供了访问const E类型的对象的阵列。

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

在第二个示例中,正如Kerrek SB所述,您阻止了前面提到的复制密切并导致移动的额外开销。

+0

似乎是一个'vector(std :: initializer_list &&)'会很有用:( –

5

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

正确。

那么为什么复制构造函数被调用?不应该调用移动构造函数吗?

不幸的是,它不可能从std::initializer_list,这是std::vector这个构造函数使用。

传递移动(A(10)),移动(A(20)),移动(A(30))代替

在这种情况下,或者复制或移动的构造被调用。发生了什么?

因为std::move转换可以防止复制拆分,所以std::initializer_list的元素在移动时不会被删除。然后,向量的构造函数从列表中复制。

相关问题