簡體   English   中英

auto a = A(3)和A a(3)有什么區別?

[英]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); 足夠了。

您為什么期望兩個代碼路徑都相同?

顯然,在第二個示例中,您正在構造一個未命名的對象,分配aauto a ),然后將其從臨時對象復制到a (這是一個步驟,因為我們正在談論臨時對象)。

兩種情況下編譯器都將生成相同的代碼無關緊要,因為在編譯時需要定義必要的函數/構造函數。 這樣想吧-優化將在編譯/代碼解析之后進行,但最終在這種情況下,代碼(應該)是相同的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM