2016-04-13 53 views
2

正如預期的那樣以下不會編譯:移動構造繞過拷貝構造函數

class A { 
public: 
    A() = default; 
    //A(A&&) = default; 
    A(const A&) = delete; 
    int x; 
}; 

int main() 
{ 
    auto a4 = A{}; // not ok, copy constructor is deleted 
    auto a5 = A(); // not ok, copy constructor is deleted 
    return 0; 
} 

但如果添加一個移動的構造函數,即使拷貝構造函數顯式刪除,那麼下面就編譯:

class A { 
public: 
    A() = default; 
    A(A&&) = default; 
    A(const A&) = delete; 
    int x; 
}; 

int main() 
{ 
    auto a4 = A{}; // now ok, even though copy constructor is deleted 
    auto a5 = A(); // now ok, even though copy constructor is deleted 
    return 0; 
} 

爲什麼不考慮刪除的拷貝構造函數?

+0

因爲「A {}」或「A()」產生可變的非常量純正確值。 – Lingxi

+0

'auto a6 = a5;'會出錯。 – Jarod42

回答

4

爲什麼不考慮刪除的拷貝構造函數?

考慮。它只是沒有使用,所以它是delete d這一事實並不重要。該規則來自[dcl.fct.def.delete]:

除了聲明它之外,隱式或顯式引用已刪除函數的程序是格式不正確的。 [注意: [...]如果函數 被重載,則僅在通過重載解析選擇函數時才引用它。 [...] 末端注]上auto a = A{};

重載解析(括號VS括號是在這種情況下相當於)發現兩個構造候選人:

A(const A&); 
A(A&&); 

之一規則選擇哪些候選人是「最好的可行」候選人是,從[over.match.best]:

鑑於這些定義,一個可行的函數F1被定義爲比另一個可行函數更好的函數 F2 if,然後
-
- 上下文是通過轉換函數進行的初始化,用於將參考 的直接引用綁定(13.3.1.6)初始化爲函數類型,返回類型的F1是相同類型的參考(即左值或右值)作爲參考 被初始化,和F2的返回類型不是

此舉構造是相同種類的參考(右值)作爲參數,而拷貝構造不是。因此它是首選並被選爲最佳可行候選人。由於A(const A&)未被重載解析選中,所以我們不是指那個構造函數,所以代碼很好。

如果我們實際使用的另一方面的拷貝構造函數(例如A a(a5)),實際上會嘗試使用拷貝構造函數,這將是病態的。

+0

這回答我。這也解釋了爲什麼如果我交換兩個構造函數中的'delete'和'default',它就不能編譯。如果移動構造函數存在,重載解析就會'鎖定'。 – wally