2016-07-29 112 views
15

考慮這個簡單的類右值與拷貝操作

class Foo 
{ 
    public: 
    Foo() = default; 
    Foo(const Foo &) = default; 
    Foo & operator=(const Foo & rhs) 
    { 
     return *this; 
    } 
    Foo & operator=(Foo && rhs) = delete; 
}; 

Foo getFoo() 
{ 
    Foo f; 
    return f; 
} 

int main() 
{ 
    Foo f; 
    Foo & rf = f; 
    rf = getFoo(); // Use of deleted move assignment. 
    return 0; 
} 

當我編譯上面的例子中,我得到error: use of deleted function 'Foo& Foo::operator=(Foo&&)'

Copy Assignment

如果只提供拷貝賦值,所有參數類別選擇它(只要它通過值或作爲const引用的參數,因爲rvalues可以綁定到const引用),這使得副本分配成爲m的後備當移動不可用時

爲什麼編譯器後備時複製分配時常量左值引用可以綁定到右值和const Foo & f = getFoo();工程。

編譯器 - gcc 4.7.2。

回答

10

沒有後備,該概念被稱爲重載分辨率

編譯器執行重載決策並在檢查方法是否被刪除之前作出決定。 編譯器決定移動構造函數是最佳選擇,那麼它確定此方法已被刪除,因此出現錯誤。

注1: delete並不會逐字刪除該方法。如果使用delete,則方法是定義爲刪除,但它仍可以通過重載解析找到。

cppreference.com文檔(重點礦山):

... 重載首先發生,程序只是如果被刪除的功能選擇形成不良。

在您的例子中,移動構造函數可用(從視重載解析點)。但是,它被定義爲刪除

注意2:如果您不想讓您的類具有移動構造函數,則不要定義它。如果您聲明瞭以下其中一項,則編譯器將不會生成移動構造函數:複製構造函數,複製賦值運算符,移動賦值運算符,析構函數。

+0

難道你不是指「移動構造函數*可用*」嗎? – Quentin

+0

@Quentin你是對的,謝謝!編輯。 – sergej

8

編譯器正在做你所要求的。您已刪除移動賦值運算符,這表示您不希望允許從右值分配。移動賦值操作符將在重載解析期間找到,並且由於它被刪除,所以會發出診斷。

如果您只是聲明瞭複製賦值運算符,那麼移動賦值運算符將不會被隱式聲明,所以不會通過重載解析找到,而是會調用複製賦值運算符。

4

該報價可能有點誤導。

如果由於明確聲明瞭複製分配而未完全聲明移動分配,則具有r值的調用將「回退」至複製分配。

但是,您已明確聲明瞭移動作業,並將其刪除。因此移動分配的聲明「可用」,並且解析爲已刪除的定義。