簡體   English   中英

為什么使用std :: vector :: push_back的move變量會調用移動項的復制構造函數?

[英]Why does using the move variant of std::vector::push_back invoke the moved item's copy constructor?

這里有一些代碼無法編譯,因為push_back試圖在MoveOnlyClass中調用復制構造函數,該構造函數被刪除:

class MoveOnlyClass
{
public:
    MoveOnlyClass() {};
    MoveOnlyClass& operator=(const MoveOnlyClass& other) = delete;
    MoveOnlyClass(const MoveOnlyClass& other) = delete;
};

int main()
{
    std::vector<MoveOnlyClass> vec;
    vec.push_back(std::move(MoveOnlyClass()));
}

為什么會這樣? 當然,向量應該調用的唯一東西是移動構造函數。 將對象移動到向量中的正確方法是什么?

刪除復制構造函數/復制賦值函數也會隱式刪除move-constructor / move賦值函數。 如果您打算使對象可移動但不可復制,則還需要default移動構造函數。

class MoveOnlyClass
{
public:
    MoveOnlyClass() {};
    MoveOnlyClass& operator=(const MoveOnlyClass& other) = delete;
    MoveOnlyClass(const MoveOnlyClass& other) = delete;
    MoveOnlyClass& operator=(MoveOnlyClass&& other) = default;
    MoveOnlyClass(MoveOnlyClass&& other) = default;
};

//Will now compile as you expect
int main()
{
    std::vector<MoveOnlyClass> vec;
    vec.push_back(std::move(MoveOnlyClass()));
}

另外, std::move(T())是多余的; 像這樣構造一個就地對象已經使它成為一個R值,並且當你不需要時使用std::move可能會阻止某些類型的編譯器優化(比如Copy Ellision)。

@Xirema的答案密切關於代碼中問題的處理,並解釋了為什么會這樣。

我只是想用語言規范的適當摘錄來支持它,以使事情正式化。 所以來自[class.copy.ctor¶8]

(8)如果類X的定義沒有顯式地聲明一個移動構造函數, 那么當且僅當一個非顯式的構造函數被隱式聲明為默認的

  • (8.1) X沒有用戶聲明的拷貝構造函數

為此我們應該添加聲明,因為刪除仍然是聲明。 因此,根據這一點,我們不會在您的情況下獲得隱式聲明的移動構造函數 ,因為我們已經有了一個用戶聲明的復制構造函數

此外,在[dcl.fct.def.delete¶3]下

通過使用復制構造函數和復制賦值運算符的已刪除定義, 然后提供移動構造函數和移動賦值運算符的默認定義, 可以使類不可復制,即僅移動。

暫無
暫無

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

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