2014-02-21 23 views
0

如果一個對象實際移動到另一個位置,原始對象上支持的操作是什麼?對象移動後支持什麼操作?

爲了闡述它,我有一個T類型的可用移動構造函數。用下面的語句

T x{constructor-args}; 
T y{std::move(x)}; 

什麼都可以與對象x來完成(前提是該對象實際上是從x使用T可移動構造函數移至y)?

具體來說,

  • x可以被毀滅,是肯定的。移動後,我可以假設x是輕微破壞嗎?
  • 可以x被分配或移動分配給一個新的對象(我猜是的,因爲我看到很多swap使用這個)?
  • 我可以構造一個新的對象對象來代替x?如果有機會這是允許的,那麼是否有可能有一個uninitialized_move與(部分)重疊的源&目標範圍一起使用,如std::copy而不像std::uninitialized_copy

    T z{some-args}; 
    x = z; //or x = std::move(z); 
    T u{some-args}; 
    new(&x) T{std::move(u)}; // or new(&x) T{u}; etc 
    

回答

2

至於庫類型,標準說(17.6.5.15)

除非另有規定,如移動,從對象應放置在一個有效的,但不確定狀態。

這意味着它們至少應該是可破壞和可分配的。正如詹姆斯在下面提到的,該對象應該仍然遵守它自己的接口。你自己的類型應該遵循相同的想法。

您不應該使用placement-new來處理這類事情。假設移動構造函數不存在,並使用operator =以與以前相同的方式編寫代碼。您示例中的最後一行應該是x=std::move(u);x=u;

+2

這意味着更多。例如,對於'std :: vector',一個有效但未指定的狀態意味着如果'v'已經被移動了,你仍然可以爲(size_t i = 0; i!= v)調用'v.size()'。 size(); ++ i)v [i];'必須仍然有效,'v.push_back(something);'必須工作。在實踐中,如果你支持銷燬,支持'std :: vector'則不會有太多的工作,但對於更復雜的類型,它可能會有所作爲。 –

+0

你說得對,但我正在談論一個明智的移動操作符的*最普遍*的要求。 – spraff

+0

是的。這正是我的觀點。最普通的要求比標準要求的要低。 –

3

無論你如何定義它。至少,由此產生的 對象應該是可銷燬的—其析構函數將調用 ,並且該對象的狀態應該是這樣的,以致該 不會導致任何問題。

標準庫保證其對象是一些 相干狀態。你可以調用任何的成員函數:它是 不確定你的回報,得到卻又結果將是 一致的:如果你調用一個矢量size該被移動, 您也可以撥打operator[]與索引小於size返回的值 (但在唯一合理的實現中, size將返回0)。然而,這可能比有效使用所需的 更多;所有這一切真的需要 是調用析構函數將工作。

使其更清晰,使用std::vector作爲一個例子:如果我們 假設通常的實現,有三個三分球,開始, 結束以及限制(但他們被稱爲:極限,就是要 一個過去的結束的分配內存,以便capacity() 返回limit - begin)。移動後,標準 要求所有三個指針都爲空。在大多數 實現中,限制指針將不會在 析構函數中訪問,因此如果僅將開始和結束指針設置爲空,則可以刪除的寬鬆要求將被滿足 。

+0

所以,我假設賦值(複製和移動)是允許的,而不是放置結構。然後,假設按照p1,p2,p3的順序給出三個指針,其中[p1,p2]是原始存儲器,[p2,p3]包含T類型的某些對象,在範圍中移動它們的最佳方式是[p1 ,p1 +(p3-p2))?我的猜測是,帶有'move_iterator'的'uninitialized_copy'不會起作用,因爲有些對象可能會在移動位置構建移動。 – abir

+0

@abir你想複製它們,還是移動它們? (但我不確定你的問題是什麼。) –

+0

將p1,p2開始的幾個地方的[p2,p3)上的對象移回去。所以我想,我必須分別根據原始內存[p1,p2]和包含移動對象[p2,p3 + p1-p2)的內存做一些'uninitialized_move'和'move'的組合。 – abir

相關問題