2017-08-25 151 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的元素在移動時不會被刪除。然後,向量的構造函數從列表中複製。

相關問題