簡體   English   中英

從const引用移動構造

[英]Move construction from const reference

我有以下情況需要從t1移動構造t2。 不幸的是,我不可能這樣做(我猜想是constness違規)
從foo的調用者那里透明地處理它的正確方法是什么? (即不需要傳遞值和顯式的std :: move)

struct T
{
    T() = default;
    ~T() = default;
    T(T&&) = default;
};

T foo(const T& t) 
{
    T t3;

    if (predicate)
        return t3;
    else
        return std::move(t);
}

int main()
{
  T t1;
  T t2 = foo(t1);

  return 0; 
}

從foo的調用者那里透明地處理它的正確方法是什么?

你不能這樣做,而那是打算這樣做的。 左值永遠不會透明地移動。

由於移動的對象通常處於未知(但合法)狀態,如果客戶端可以將左值作為參數傳遞給函數,並且允許該函數以靜默方式從其中移動,那將是危險的。 客戶端可能會留下一個僵屍對象,甚至不知道它!

因此,該語言強制執行從左值移動必須是有意識的動作的規則,並且應該通過調用std::move()將左值明確地轉換為右值(實際上是x值)來實現。

在這種情況下,我會說你的函數foo() - 無論它實際應該做什么 - 應該采用右值引用,客戶端應該像這樣調用它:

T t2 = foo(std::move(t1)); 

請注意,一旦將無意義的名稱(如foo()轉換為反映某些具體程序中某些特定操作的語義的內容,這最后的建議可能不正確。 然而,在不知道該操作的含義的情況下,我只能提供有關如何編譯代碼片段的正式機械建議,以及如何考慮移動語義。

不需要傳遞值和顯式的std :: move

如果沒有至少其中一個,C ++不會讓你移動。 這是設計的

C ++中的基本運動規則是不允許偶然發生。 如果你有一個左值,並且你想將它傳遞給一些可能從它移動的函數,那么你作為調用者必須使用std::move 這是設計的,因此很明顯調用者的意圖是移動對象。

這樣,當你掃描代碼時,你可以看到你是否意外地以不正確的方式使用了移動值​​,而不必看到除了顯式使用std::move之外的任何內容。

你想要的不是你想要的東西。

如果你想要足夠嚴重,你可以這樣做。 要做到這一點,你的foo最終將基本上重新實現std::move

struct T
{
    T() = default;
    ~T() = default;
    T(T&&) = default;
};

template<class T> struct my_remove_reference      {typedef T type;};
template<class T> struct my_remove_reference<T&>  {typedef T type;};

// The third part of a normal `remove_reference`, but which we don't need in
// this case (though it'll all still be fine if you un-comment this).
//template<class T> struct my_remove_reference<T&&> {typedef T type;};

template <typename T>
typename my_remove_reference<T>::type &&foo(T &&t) {
    return static_cast<typename my_remove_reference<T>::type &&>(t);
}

int main()
{
  T t1;
  T t2 = foo(t1);

  return 0; 
}

現在,盡管你可以/可以做到這一點,但其他答案仍然或多或少是正確的 - 即使你做到,你幾乎肯定不應該這樣做 如果你在一個支持移動構造的真實類上使用這個foo (即,真的會將狀態從源移動到目標),你最終會破壞你的源對象,即使它仍然可見。

使用您編輯的問題執行此操作, foo可以(但不總是)銷毀源對象,這將是特別有害的。 使用正確的名稱可以清楚地知道foo真的從源頭移動了,它可能只是勉強合理地做到這一點 - 但是(至少對我而言)一個可能會或可能不會破壞其論證的函數似乎顯着惡化而不是一個可靠的。 顯然,像上面那樣std::move做同樣事情的foo版本是沒有意義的,但是對輸入做了一些其他處理的版本(並且,無論出於何種原因,不能與std::move一起使用std::move )可能,可能,如果你真的沒有任何其他選擇,只是勉強可以接受。

暫無
暫無

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

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