簡體   English   中英

為什么需要在移動構造函數的初始化列表中使用std :: move?

[英]Why do I need to use std::move in the initialization list of a move-constructor?

假設我有一個(瑣碎的)類,它是可移動構造的和可移動分配的,但不能復制構造或可復制分配的類:

class movable
{
  public:
    explicit movable(int) {}
    movable(movable&&) {}
    movable& operator=(movable&&) { return *this; }
    movable(const movable&) = delete;
    movable& operator=(const movable&) = delete;
};

這工作正常:

movable m1(movable(17));

當然,這是行不通的,因為m1不是右值:

movable m2(m1);

但是,我可以將m1包裝在std::move ,將其強制轉換為右值引用,以使其正常工作:

movable m2(std::move(m1));

到現在為止還挺好。 現在,讓我們說我有一個(平凡的)容器類,它包含一個值:

template <typename T>
class container
{
  public:
    explicit container(T&& value) : value_(value) {}
  private:
    T value_;
};

但是,這不起作用:

container<movable> c(movable(17));

編譯器(我嘗試過clang 4.0和g ++ 4.7.2)抱怨我試圖在container的初始化列表中使用movable的deleteed-constructor。 同樣,將value包裝在std::move使其起作用:

    explicit container(T&& value) : value_(std::move(value)) {}

但是為什么在這種情況下需要std::move value已經不是movable&&類型的value了嗎? value_(value)movable m1(movable(42))有何不同?

這是因為value是一個命名變量,因此是一個左值。 需要std::move將其強制轉換回右值,以使T移動構造函數重載匹配。

換句話說:右值引用可以綁定到右值,但它本身不是右值。 它只是一個引用,在表達式中是一個左值。 從中創建右值表達式的唯一方法是強制轉換。

value_(value)movable m1(movable(42))有何不同?

命名的右值引用是左值(因此將綁定到已刪除的副本ctor),而臨時表是右值(具體來說是prvalue)。

§5 [expr] p6

[...]通常,此規則的作用是將已命名的右值引用視為左值,將對對象的未命名的右值引用視為x值[...]

以及從示例:

A&& ar = static_cast<A&&>(a);

表達式ar是一個左值。

上面的引文來自非規范性注釋,但由於第5節的其余部分繼續說明了哪些表達式創建xvalues (又名,僅指定的表達式而其他都不創建xvalue),因此提供了足夠的說明。 另請參閱此處以獲取詳盡列表。

†xvalues是rvalues的一個子組,而prvalues是rvalues的另一子組。 請參閱此問題以獲取解釋。

暫無
暫無

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

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