我不太確定這裏要走的路是什麼;如果我有一個帶有指針成員的類和一個將指針成員設置爲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;
}
把測試空到處會降低性能,這如果用戶知道訪問移動的而不是重新初始化的對象是未定義的行爲,則將是不必要的。 這是怎麼回事?
如果'init()'是一個只從構造函數調用的私有函數呢?您的解釋似乎基於假設'init()'或任何像存在的公共函數那樣的函數,而我只是將它放在我的示例中,以便從未指定數目的成員的初始化中抽象出來。 –
嗯,那完全是假設。但是,如果它是私人的話也是一樣。假設你的對象期望'init'總是從構造函數中調用。你可以天真地編寫代碼,並使移動構造函數調用'init',然後將所有成員與目標交換。但是,希望你現在會意識到,因爲對象可以處於未指定狀態,所以如果在嘗試使用後移動後崩潰,則沒有人會抱怨。你唯一需要確保的是析構函數已經定義了行爲,即使'init'從未被調用(並且指針成員都是NULL)。 – paddy
這就是爲什麼交換是一種非常常見的移動方式:您只需切換所有內容,並且您知道這兩個對象都處於有效狀態。這意味着你不必在你的移動構造函數中做一些棘手的事情,比如構造函數和/或析構函數的重複部分。實際上,一些實際上會爲它們的類實現'swap'來完成這個操作,然後直接調用它來移動:'C :: C(C && c){std :: swap(* this,c); }' – paddy