[英]C++11 move constructor
考慮以下類,實現移動構造函數的正確方法是什么:
class C {
public:
C();
C(C&& c);
private:
std::string string;
}
當然,其想法是避免復制string
或將其重新分配兩次。
讓我們假設基本示例只是為了清楚起見,我確實需要一個move構造函數。
我試過了:
C::C(C&& c) {
//move ctor
string = std::move(c.string);
}
和
C::C(C&& c) : string(std::move(c.string)) {
//move ctor
}
兩者都可以在gcc 4.8上正常編譯,並且可以正常運行。 看來選項A是正確的行為, string
被復制而不是與選項B一起移動。
這是move構造函數的正確實現嗎?
由於std::string
本身具有move-ctor,因此C
隱式定義的move-ctor將負責適當的move操作。 您可能無法自己定義。 但是,如果您有任何其他數據成員,尤其是:
12.8復制和移動類對象
12隱式聲明的copy / move構造函數是其類的內聯公共成員。 如果X具有以下功能,則默認將類X的復制/移動構造函數定義為已刪除(8.4.3):
—具有非平凡的對應構造函數且X是類聯合類的變體成員,
—無法復制/移動的類類型M(或其數組)的非靜態數據成員,因為應用於M的相應構造函數的重載分辨率(13.3)導致歧義或函數從該類中刪除或不可訪問默認的構造函數,或者
—無法復制/移動的直接或虛擬基類B,因為將重載解析(13.3)應用於B的相應構造函數,會導致歧義或從默認構造函數中刪除或無法訪問的函數,或者
—對於move構造函數,是非靜態數據成員或直接或虛擬基類,其類型沒有move構造函數且不可復制。
13如果類X的復制/移動構造函數既不是用戶提供的也不是用戶刪除的,並且
—類X沒有虛擬函數(10.3)和虛擬基類(10.1),函數(10.3)和虛擬基類(10.1),以及
—選擇復制/移動每個直接基類子對象的構造函數很簡單,並且
—對於類類型(或其數組)的X的每個非靜態數據成員,選擇用來復制/移動該成員的構造函數都是微不足道的; 否則,復制/移動構造函數是不平凡的。
您可能想實現自己的move-ctor。
如果您需要move-ctor,請使用初始化列表語法。 總是! 否則,您可能會為每個對象的默認構造最終在初始化列表中未提及(這是僅對具有非默認ctor的成員對象強制執行的操作)。
您的兩個變體都會移動字符串。 第二個變體應該是首選,因為它不會默認構造一個空字符串,只是隨后移動分配它。
檢查您的測試用例,然后檢查編譯器的bugzilla列表。 如果要確保兩種情況都移動,則需要跟蹤對string::operator=(string&&)
(第一種情況) 和 string::string(string&&)
(第二種情況)的調用。
兩個構造函數都應該工作。 因此,兩者都是正確的move構造函數。 第二個可能會更有效,因為第一個默認構造string
只是為了分配給它,而第二個默認只是移動構造它,因此應該更有效。 如果第二個效率較低,我會懷疑是編譯器錯誤(請記住,當前編譯器對C ++ 11的支持仍不完整)或測試方法有缺陷(您將如何精確地測試復制與移動,並且確定移動構造函數是否正確)兩種情況下都不會調用賦值操作嗎?)。
當然,只要有可能,您只要讓編譯器通過C(C&&) = default;
生成您的構造函數即可C(C&&) = default;
。
此處無需實現move構造函數,因為您不必手動管理內存。 僅當在類中手動使用動態數組時,移動構造函數才有用。
您仍然可以顯式地讓編譯器創建默認的move構造函數,即使您不要求它也應該已經完成:
C(C&& c) = default;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.