我創建了一個類Animal:
class Animal {
public:
Animal() = default;
Animal(Animal&& a) = delete;
Animal(Animal& a) = delete;
Animal& operator=(Animal&& a) = delete;
Animal& operator=(Animal& a) = delete;
};
Animal func1() {
return Animal();
}
Animal func2() {
Animal a {};
return a;
}
int main(void) {
Animal a1 = func1();
Animal a2 = func2();
return 0;
}
我不明白為什么func1()可以正常作業:return Animal()創建一個右值物件并a1在函式中使用該物件進行初始化main;如我所見,它等于
Animal a1 = func1()
==
Animal a1 = Animal&& temp //(I wrote type in assignment for clarifying)
我已經讀過回傳值是一個右值;但是,在func2我得到一個錯誤,“復制建構式被洗掉”而不是移動建構式,為什么?
uj5u.com熱心網友回復:
情況1
在這里,我們考慮以下宣告:
Animal a1 = func1();
呼叫運算式func1()是一個rv型別的值Animal。從 C 17 開始,由于強制復制 elison:
在以下情況下,編譯器必須省略類物件的復制和移動構造,即使復制/移動建構式和解構式具有可觀察到的副作用。物件直接構建到存盤中,否則它們將被復制/移動到。復制/移動構造函式不需要存在或可訪問:
- 在 return 陳述句中,當運算元是與函式回傳型別相同的型別別(忽略 cv 限定)的純右值時:
也就是說,物件直接構建到存盤中,否則它們將被復制/移動到。也就是說,在這種情況下(對于 C 17),不需要可用的復制/移動建構式。所以這個宣告有效。
案例2
在這里,我們考慮以下宣告:
Animal a2 = func2();
這里來自非強制性復制 elison,
在以下情況下,編譯器允許但不需要省略類物件的復制和移動(C 11 起)構造,即使復制/移動(C 11 起)建構式和解構式具有可觀察的一面-效果。物件直接構建到存盤中,否則它們將被復制/移動到。這是一種優化:即使它發生并且沒有呼叫復制/移動(自 C 11 起)建構式,它仍然必須存在且可訪問(就好像根本沒有發生任何優化一樣),否則程式會出錯 -形成:
- 在 return 陳述句中,當運算元是具有自動存盤持續時間的非易失性物件的名稱時,它不是函式引數或 catch 子句引數,并且屬于相同的型別別(忽略 cv 限定)函式回傳型別。
也就是說,復制/移動建構式必須存在(即這些 ctor 必須存在且可訪問),但由于您已明確將它們標記為已洗掉,因此此陳述句失敗并出現錯誤:
error: use of deleted function ‘Animal::Animal(Animal&&)’
錯誤也可以在這里看到
uj5u.com熱心網友回復:
在 C 17 中有一組關于臨時實作的新規則。
在一個簡單的解釋中,計算為純右值(臨時值)的運算式不會立即創建物件,而是創建物件的方法。因此,在您的示例Animal()中,不會立即創建物件,因此即使洗掉了復制和移動建構式,您也可以回傳它。
在您的主要分配prvaluea觸發臨時物化,因此該物件現在只是直接在范圍內創建main。通過所有這一切,只有一個物件,因此沒有復制或移動操作。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/463585.html
