struct MZEntry
{
uint32_t machineID;
bool mode;
uint32_t area;
uint32_t occupancy;
using ZList = std::vector<uint32_t>;
ZList authorisationZ;
ZList blockExceptionZ;
void clear()
{
machineID = 0;
mode = false;
area = 0;
occupancy = 0;
authorisationZ.clear();
blockExceptionZ.clear();
}
MZEntry(){
clear();
}
MZEntry(const MZEntry& mzEntry)
{
machineID = mzEntry.machineID;
mode = mzEntry.mode;
area = mzEntry.area;
occupancy = mzEntry.occupancy;
authorisationZ = mzEntry.authorisationZ;
blockExceptionZ = mzEntry.blockExceptionZ;
}
};
我的代碼中有上述結構。我明確宣告復制建構式有什么好處嗎?
假設我有兩個變數
MZEntry entry_1;
MZEntry entry_2;
如果我這樣做了,是否會復制其中的entry_1 = entry_2所有欄位以包括其中的向量?entry_2entry_1
或者是否需要顯式復制建構式。上面的顯式復制建構式也更有效嗎?
uj5u.com熱心網友回復:
宣告復制建構式是個壞主意。盡可能遵循零規則,如果您不需要自定義解構式行為,則不要宣告任何復制/移動建構式或賦值運算子或解構式,因為該類必須管理某些資源(如果必須,請始終封裝遵循五規則(或三規則),在一個專門限于該目的的課程中。另請參閱C 核心指南。
如果您手動宣告復制建構式,您將禁止移動操作的隱式定義,該操作將盡可能使用而不是復制操作來執行成員的移動有效移動(而不是復制)。
例如
MZEntry entry_1;
MZEntry entry_2;
/*...*/
entry_1 = std::move(entry_2);
使用(隱式)移動賦值運算子,這允許entry_1只接管向量成員entry_2分配的記憶體。entry_2之后將處于未指定的狀態,但這通常很好。使用復制建構式的手動宣告,將不會有隱式移動賦值運算子,并且上面將執行所有向量元素的完整副本,與entry_1 = entry_2(使用或不使用手動定義的復制建構式)相同。
此外,正如問題評論中所提到的,您的復制建構式的實作實際上比編譯器生成的性能更差,盡管它最終會產生完全相同的行為。
類似地,可以通過使用類內默認成員初始值設定項來避免手動定義默認建構式,并讓編譯器從中生成默認建構式。
呼叫.clear()向量成員是多余的,因為它們的默認建構式無論如何都會將它們置于空狀態。
遵循核心準則,您將擁有:
struct MZEntry
{
uint32_t machineID = 0;
bool mode = false;
uint32_t area = 0;
uint32_t occupancy = 0;
using ZList = std::vector<uint32_t>;
ZList authorisationZ;
ZList blockExceptionZ;
};
或者(同樣的結果,風格問題):
struct MZEntry
{
uint32_t machineID{};
bool mode{};
uint32_t area{};
uint32_t occupancy{};
using ZList = std::vector<uint32_t>;
ZList authorisationZ{};
ZList blockExceptionZ{};
};
這使編譯器可以優化生成所有特殊成員函式。如果您需要該clear方法用于其他目的,則可以簡單地實作為
void clear() {
*this = MZEntry();
}
或(同樣是風格問題,同樣的結果):
void clear() {
*this = {};
}
(盡管您對成員函式的更顯式實作clear可能整體上性能更高,因為它不會導致向量的記憶體被釋放,因此它們可以稍后在沒有新分配的情況下重用它。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/497379.html
