我有下面的類并嘗試添加復制和移動建構式和賦值運算子。我的目標是擁有最少的副本并盡可能優化。
我希望將向量填充到位,即在創建向量時不會呼叫復制建構式。我做錯了什么以及如何強制它使用移動建構式或賦值?
#include <iostream>
#include <concepts>
#include <vector>
template<typename T>
requires std::is_arithmetic_v<T>
class Data {
private :
T mA = 0;
T mB = 0;
public:
Data(const T& data) : mA{data}{ // from single T
std::cout << "Constructed Data with: " << mA << ", " << mB << std::endl;
}
Data(const Data<T>& other) : mA{other.mA}, mB{other.mB} {
std::cout << "COPY Constructed Data with: " << mA << ", " << mB << std::endl;
}
Data(Data<T>&& other) : mA{other.mA}, mB{other.mB} {
std::cout << "MOVE Constructed Data with: " << mA << ", " << mB << std::endl;
}
Data(const std::initializer_list<T>& list) {
std::cout << "Constructed Data with list: ";
if(list.size() >= 2) {
mA = *list.begin();
mB = *(list.begin() 1);
std:: cout << mA << ", " << mB << std::endl;
}
}
~Data() {
std::cout << "Destructed: " << mA << ", " << mB << std::endl;
}
const Data operator=(const Data& other) {
mA = other.mA;
mB = other.mB;
return *this;
}
Data operator=(Data&& other) {
mA = other.mA;
mB = other.mB;
return *this;
}
};
int main() {
std::cout << "** With initilizer_list **" << std::endl;
{
auto vec = std::vector<Data<int>>{{1,1}, {2,2}};
}
std::cout << "\n**With element**" << std::endl;
{
auto vec = std::vector<Data<int>>{1,2};
}
std::cout << "\n**With push**" << std::endl;
{
auto vec = std::vector<Data<int>>();
vec.push_back(1);
vec.push_back(2);
}
}
輸出:
** With initilizer_list ** Constructed Data with list: 1, 1 Constructed Data with list: 2, 2 COPY Constructed Data with: 1, 1 COPY Constructed Data with: 2, 2 Destructed: 2, 2 Destructed: 1, 1 Destructed: 1, 1 Destructed: 2, 2 **With element** Constructed Data with: 1, 0 Constructed Data with: 2, 0 COPY Constructed Data with: 1, 0 COPY Constructed Data with: 2, 0 Destructed: 2, 0 Destructed: 1, 0 Destructed: 1, 0 Destructed: 2, 0 **With push** Constructed Data with: 1, 0 MOVE Constructed Data with: 1, 0 Destructed: 1, 0 Constructed Data with: 2, 0 MOVE Constructed Data with: 2, 0 COPY Constructed Data with: 1, 0 Destructed: 1, 0 Destructed: 2, 0 Destructed: 1, 0 Destructed: 2, 0
CompilerExplorer 鏈接
uj5u.com熱心網友回復:
我希望將向量填充到位
無論push_back和初始化串列構造想到的是,元素已建成并通過引數傳遞。因此元素必須首先通過轉換構造,然后移動/復制到向量的存盤中。如果您不想要那樣,請emplace_back改用它,它接受元素建構式的建構式引數并就地創建元素。
這并不能解決所有復制和移動的情況,因為如果舊物件變得太小而無法容納更多元素,向量必須將物件移動到新存盤。為了完全避免這種情況,首先呼叫vec.reserve(...)where...至少與向量將具有的最大大小一樣大。
在重新分配的情況下使用 copy 而不是 move 的原因是因為您沒有標記您的移動建構式noexcept。std::vector如果移動建構式不是noexcept,則更喜歡復制建構式,因為如果移動建構式在將物件移動到新存盤時拋出例外,則std::vector不能保證它能夠像通常那樣回滾到以前的狀態。
在類中宣告復制/移動建構式/賦值或解構式總是有點冒險。首先,因為導致未定義行為是多么容易,請參閱三/五規則,其次因為如果不仔細撰寫,它通常會導致比隱式生成版本更糟糕的結果。
如果您沒有特定原因,例如因為您管理類中的原始資源,則不要宣告任何這些特殊成員。(僅)然后隱式將自動執行正確且最有可能最好的事情(“零規則”)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/399077.html
上一篇:Helm模板檢查布林值
下一篇:存盤格式化的字串,稍后傳入值?
