2016-09-22 27 views
1

我不太確定這裏要走的路是什麼;如果我有一個帶有指針成員的類和一個將指針成員設置爲nullptr的移動構造函數,並且移動函數是可以將指針成員設置爲0的唯一函數,那麼我是否需要在任何地方都將測試置零:我解引用的成員,因爲該對象可能已被傳遞給移動構造函數?一旦我有移動功能,我是否需要在所有地方添加空測試?

例如,函數

unisgned size() 
{ 
    return memberpointer->size(); 
} 

將成爲

unisgned size() 
{ 
    if memberpointer == nullptr 
     return 0; 
    return memberpointer->size(); 
} 

否則當然這將給段錯誤如果size()被稱爲移動的對象上。這是否是用戶的錯,或者是我的錯,因爲沒有構建一個空測試?如果用戶不重新初始化之前訪問移動的對象,這可能不是隻要我把在拷貝賦值運算符的空測試發生:

C& operator=(C& src) 
    { 
     if (this != &src) 
     { 
      if (memberpointer == nullptr) 
       init(); 
      *memberpointer = *src.memberpointer; 
     } 
     return *this; 
    } 

把測試空到處會降低性能,這如果用戶知道訪問移動的而不是重新初始化的對象是未定義的行爲,則將是不必要的。 這是怎麼回事?

回答

2

不,沒有必要進行所有這些測試,比如果您根本沒有移動語義。如果在調用某種初始化函數之前使用對象是非法的,那麼在移動後使用該對象也應該認爲是非法的。你的對象應該處於一個可以正常破壞的狀態,但是沒有其他規則指定應該是什麼狀態。

例如:

Foo foo; 
foo.Init(); // required 
// foo is now allowed to be used 

Foo bar = std::move(foo); 
// No guarantees on whether foo is now initialised or not. 

移動語義並沒有規定什麼狀態的對象移動從後招會英寸它只要求對象處於某種內部一致的狀態。因此,您的移動構造函數或賦值運算符完全有權swap成員(如果它希望的話)...提供該對象的所有其他內部狀態與此一致。也就是說,這是完全沒關係有這種情況:

Foo foo, bar; 
foo.Init(); 
bar.Init(); 
bar = std::move(foo); 
// foo and bar contents now swapped. 
// caveat: you should not use foo again 

但是,你不能指望。規則是在移動之後,您不應該嘗試再次使用該對象。

+0

如果'init()'是一個只從構造函數調用的私有函數呢?您的解釋似乎基於假設'init()'或任何像存在的公共函數那樣的函數,而我只是將它放在我的示例中,以便從未指定數目的成員的初始化中抽象出來。 –

+1

嗯,那完全是假設。但是,如果它是私人的話也是一樣。假設你的對象期望'init'總是從構造函數中調用。你可以天真地編寫代碼,並使移動構造函數調用'init',然後將所有成員與目標交換。但是,希望你現在會意識到,因爲對象可以處於未指定狀態,所以如果在嘗試使用後移動後崩潰,則沒有人會抱怨。你唯一需要確保的是析構函數已經定義了行爲,即使'init'從未被調用(並且指針成員都是NULL)。 – paddy

+1

這就是爲什麼交換是一種非常常見的移動方式:您只需切換所有內容,並且您知道這兩個對象都處於有效狀態。這意味着你不必在你的移動構造函數中做一些棘手的事情,比如構造函數和/或析構函數的重複部分。實際上,一些實際上會爲它們的類實現'swap'來完成這個操作,然後直接調用它來移動:'C :: C(C && c){std :: swap(* this,c); }' – paddy

0

C++標準庫通過將移動對象置於「有效但未指定」狀態解決了這個問題:換句話說,您可以對其進行操作,使用它不會導致程序崩潰,但唯一可以預測的是do是寫信給它重新建立一個已知的狀態。

如果您的默認構造函數沒有將指針留空,那麼您的移動構造函數不應該:它應該將move-from對象保留在可以安全地調用成員但不依賴於任何特定值。如果您的默認構造函數將指針留空(null),那麼對於移動構造函數來說顯然也沒有問題。

+0

但是之後我需要在從它們移出後用'memberpointer = new T'重新初始化成員,我會不會? –

+0

@lotolmencre:那麼只需複製一份?目前還不清楚,因爲你沒有顯示任何真實的代碼。 – GManNickG

+0

所以答案實際上取決於memberPointer是否可以爲null,這是作者必須做出的設計決定? –

相關問題