Discussion: Define Copy, move, and destroy consistently
討論:保持定義複製,移動和析構函數的一致性git
Reason(緣由)
???github
Note(注意)web
If you define a copy constructor, you must also define a copy assignment operator.express
若是定義了拷貝構造函數,則還必須定義一個拷貝賦值運算符。編程
Note(注意)設計模式
If you define a move constructor, you must also define a move assignment operator.安全
若是定義了移動構造函數,則還必須定義一個移動賦值運算符。微信
Example(示例)架構
class X {
public:
X(const X&) { /* stuff */ }
// BAD: failed to also define a copy assignment operator
X(x&&) noexcept { /* stuff */ }
// BAD: failed to also define a move assignment operator
// ...
};
X x1;
X x2 = x1; // ok
x2 = x1; // pitfall: either fails to compile, or does something suspicious
If you define a destructor, you should not use the compiler-generated copy or move operation; you probably need to define or suppress copy and/or move.app
若是定義了析構函數,則不該使用編譯器生成的複製或移動操做。您可能須要定義或抑制複製和/或移動操做。
class X {
HANDLE hnd;
// ...
public:
~X() { /* custom stuff, such as closing hnd */ }
// suspicious: no mention of copying or moving -- what happens to hnd?
};
X x1;
X x2 = x1; // pitfall: either fails to compile, or does something suspicious
x2 = x1; // pitfall: either fails to compile, or does something suspicious
If you define copying, and any base or member has a type that defines a move operation, you should also define a move operation.
若是您在定義拷貝操做,若是任何基類或成員的類型具備移動操做,則還應該定義移動操做。
class X {
string s; // defines more efficient move operations
// ... other data members ...
public:
X(const X&) { /* stuff */ }
X& operator=(const X&) { /* stuff */ }
// BAD: failed to also define a move construction and move assignment
// (why wasn't the custom "stuff" repeated here?)
};
X test()
{
X local;
// ...
return local; // pitfall: will be inefficient and/or do the wrong thing
}
If you define any of the copy constructor, copy assignment operator, or destructor, you probably should define the others.
若是定義了拷貝構造函數,拷貝賦值運算符或析構函數中的任何一個,則可能應該定義其餘全部函數。
Note(注意)
If you need to define any of these five functions, it means you need it to do more than its default behavior -- and the five are asymmetrically interrelated. Here's how:
若是您須要定義這五個函數中的任何一個,則意味着您須要它作更多的工做而不是其默認行爲-而且這五個函數是不對稱地相互關聯的。就是這樣:
If you write/disable either of the copy constructor or the copy assignment operator, you probably need to do the same for the other: If one does "special" work, probably so should the other because the two functions should have similar effects. (See Item 53, which expands on this point in isolation.)
若是您編寫/禁用了拷貝構造函數或拷貝賦值運算符,則可能須要對另外一個函數進行相同的操做:若是一個函數執行「特殊」工做,那麼另外一個函數也應該這樣作,由於這兩個函數應具備類似的效果。(請參閱第53項,它在這一點上單獨展開。)
If you explicitly write the copying functions, you probably need to write the destructor: If the "special" work in the copy constructor is to allocate or duplicate some resource (e.g., memory, file, socket), you need to deallocate it in the destructor.
若是您顯式地編寫拷貝函數,則可能須要編寫析構函數:若是拷貝構造函數中的「特殊」工做是分配或拷貝某些資源(例如,內存,文件,套接字),則須要在析構函數中釋放它。
If you explicitly write the destructor, you probably need to explicitly write or disable copying: If you have to write a non-trivial destructor, it's often because you need to manually release a resource that the object held. If so, it is likely that those resources require careful duplication, and then you need to pay attention to the way objects are copied and assigned, or disable copying completely.
若是顯式地編寫了析構函數,則可能須要顯式地編寫或禁用拷貝操做:若是必須編寫非平凡的析構函數,一般是由於您須要手動釋放對象持有的資源。若是是這樣,則這些資源可能須要仔細複製,而後您須要注意複製和分配對象的方式,或者徹底禁用複製。
In many cases, holding properly encapsulated resources using RAII "owning" objects can eliminate the need to write these operations yourself. (See Item 13.)
在許多狀況下,使用RAII「擁有」對象保存正確封裝的資源能夠消除本身編寫這些操做的須要。(請參閱第13項。)
Prefer compiler-generated (including =default) special members; only these can be classified as "trivial", and at least one major standard library vendor heavily optimizes for classes having trivial special members. This is likely to become common practice.
首選編譯器生成的(包括= default)特殊成員;只有這些能夠歸類爲「瑣碎的」,而且至少一個主要的標準庫供應商針對具備瑣碎的特殊成員的類進行了重度優化。這極可能會成爲慣例。
Exceptions: When any of the special functions are declared only to make them non-public or virtual, but without special semantics, it doesn't imply that the others are needed. In rare cases, classes that have members of strange types (such as reference members) are an exception because they have peculiar copy semantics. In a class holding a reference, you likely need to write the copy constructor and the assignment operator, but the default destructor already does the right thing. (Note that using a reference member is almost always wrong.)
例外:當聲明任何特殊函數只是爲了使它們成爲非公共或虛擬的,而沒有特殊語義時,並不意味着須要其餘特殊功能。在極少數狀況下,具備奇怪類型的成員(例如引用成員)的類是例外,由於它們具備特殊的複製語義。在一個包含引用的類中,您可能須要編寫拷貝構造函數和賦值運算符,可是默認的析構函數已經能夠正確處理。(請注意,使用引用成員幾乎老是錯誤的。)
Resource management rule summary:
資源管理規則摘要:
Provide strong resource safety; that is, never leak anything that you think of as a resource
提供強大的資源安全性;也就是說,永遠不要泄漏任何您認爲是資源的東西
Never throw while holding a resource not owned by a handle
持有沒有被句柄擁有的資源時切勿拋出異常
A "raw" pointer or reference is never a resource handle
「原始」指針或引用毫不是資源句柄
Never let a pointer outlive the object it points to
永遠不要讓指針值的生命週期超過它所指向的對象
Use templates to express containers (and other resource handles)
使用模板來表達容器(和其餘資源句柄)
Return containers by value (relying on move or copy elision for efficiency)
按值返回容器(依靠移動或複製省略以提升效率)
If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations
若是類是資源句柄,則它須要一個構造函數,一個析構函數以及複製和/或移動操做
If a class is a container, give it an initializer-list constructor
若是類是容器,請爲其提供一個初始化器列表形式的構造函數
原文連接https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#define-copy-move-and-destroy-consistently
新書介紹
《實戰Python設計模式》是做者最近出版的新書,拜託多多關注!
本書利用Python 的標準GUI 工具包tkinter,經過可執行的示例對23 個設計模式逐個進行說明。這樣一方面能夠使讀者瞭解真實的軟件開發工做中每一個設計模式的運用場景和想要解決的問題;另外一方面經過對這些問題的解決過程進行說明,讓讀者明白在編寫代碼時如何判斷使用設計模式的利弊,併合理運用設計模式。
對設計模式感興趣並且但願隨學隨用的讀者經過本書能夠快速跨越從理解到運用的門檻;但願學習Python GUI 編程的讀者能夠將本書中的示例做爲設計和開發的參考;使用Python 語言進行圖像分析、數據處理工做的讀者能夠直接以本書中的示例爲基礎,迅速構建本身的系統架構。
以爲本文有幫助?請分享給更多人。
關注微信公衆號【面向對象思考】輕鬆學習每一天!
面向對象開發,面向對象思考!
本文分享自微信公衆號 - 面向對象思考(OOThinkingDalian)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。