[英]List initialization and copy elision
請考慮以下示例:
#include <cstdlib>
struct A
{
A(int, char*){};
A(const A&){ printf("copy-ctor\n"); }
};
int main()
{
A x = A(5, nullptr);
}
根據8.5.16(C ++ 11標准)的行
A x = A(5, nullptr);
被視為
A x(A(5, nullptr));
(即創建類型A的臨時對象並將其傳遞給類型A的copy-ctor以初始化x)。 然后根據12.8.31編譯器允許( 但不強制 )執行稱為“復制省略”的優化以消除類型A的臨時創建,這有效地使該行代碼成為
A x(5, nullptr);
(即沒有臨時創建,沒有復制者稱呼)。
現在,假設我在上面的示例中使用列表初始化,如下所示:
A x = {5, nullptr}; // (1)
要么
A x = A{5, nullptr}; // (2)
有人可以引用C ++ 11標准中適當的階段圖來確認或否認(1)和/或(2) 總是 (即不僅在編譯器可以做“復制省略”優化時)被視為
A x(5, nullptr);
(即直接調用A的第一個構造函數,不創建臨時值,不執行類型A對象的復制)。
這個答案顯然是錯誤的,這讓我感到驚訝。 查看評論。 我認為[dcl.init.list] / 3的第一個和第四個要點是什么意思(1)直接調用構造函數(或執行聚合init),沒有臨時的。
標准中沒有任何內容可以保證(1)和(2)避免臨時。 它們都是復制初始化,(1)是[dcl.init.list] p1定義的復制列表初始化:
列表初始化可以在直接初始化或復制初始化上下文中進行; 直接初始化上下文中的列表初始化稱為直接列表初始化 ,復制初始化上下文中的列表初始化稱為復制列表初始化 。
在這兩種情況下都是復制初始化,[dcl.init]表示可能涉及移動(可以省略)。
8.5/14,15
:
在表單中發生的初始化
T x = a;
[...]稱為復制初始化。
表單中發生的初始化
T x(a);
T x{a};
[...]稱為直接初始化。
如果您的編譯器不夠智能以至於總是忽略臨時,那么為了確保沒有臨時的列表初始化,您可以使用direct-list-initialization,即
A x{5, nullptr};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.