[英]What's the difference between auto a = A(3) and A a(3)?
假設我有:
struct A
{
A(int x) : m_x(x) { }
A(A&&) = delete;
int m_x;
}
和:
A a(3); // Ok
auto a = A(3); // Error: function A(int&&) cannot be referenced - it's a deleted function
后者為何調用move構造函數? 為什么這2條語句在生成代碼方面有所不同?
auto a = A(3);
與A a = A(3);
因為右側的類型是A
這意味着確切的樣子: A(3)
創建一個用3
初始化的臨時A
,然后A a = _____
意思是:創建a
以_____
作為初始化程序的A
因此,您創建了一個臨時文件,將該臨時文件傳遞給a
作為初始化程序,然后銷毀了該臨時文件。 這種類型的初始化(帶有=
)稱為復制初始化 (盡管不要將其與“復制”混淆,這只是一個詞)。
選擇一個構造函數來構造a
接受A
。 它必須是副本或移動構造函數。 A
具有移動構造函數和復制構造函數。 后者是隱式生成的,並且也定義為Deleted,因為有一個用戶聲明的move構造函數。
但是,被定義為Delete不會影響重載解析; 在這種情況下,move構造函數比copy構造函數更可取。
因此,您的代碼嘗試調用格式錯誤的delete
d函數,從而導致錯誤。
請注意,如果未刪除move-constructor,則將應用復制省略。 在某些情況下,它會從臨時變量初始化,或者按值返回局部變量。 規則是編譯器可以為a
和臨時對象使用相同的內存,並忽略對copy / move構造函數的調用。
在大多數情況下,大多數/所有編譯器都會這樣做。 因此,您實際上可以auto a = A(3);
寫auto a = A(3);
並且在實踐中不會采取任何不必要的措施。 如果您為移動構造函數編寫了一些輸出內容的代碼,則希望會發現什么都沒有輸出。
如果要絕對確定沒有不必要的副本,或者構造沒有可用副本的對象,也不要移動構造函數-停止編寫指定不必要副本的代碼! A a(3);
足夠了。
您為什么期望兩個代碼路徑都相同?
顯然,在第二個示例中,您正在構造一個未命名的對象,分配a
( auto a
),然后將其從臨時對象復制到a
(這是一個步驟,因為我們正在談論臨時對象)。
兩種情況下編譯器都將生成相同的代碼無關緊要,因為在編譯時需要定義必要的函數/構造函數。 這樣想吧-優化將在編譯/代碼解析之后進行,但最終在這種情況下,代碼(應該)是相同的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.