C++ 深度复制和移动支持
示例
如果类型希望具有值语义,并且它需要存储动态分配的对象,那么在复制操作中,该类型将需要分配这些对象的新副本。它还必须执行此操作以进行副本分配。
这种复制称为“深层复制”。它有效地吸收了原本应该是引用语义的内容,并将其转换为值语义:
struct Inner {int i;};
const int NUM_INNER = 5;
class Value
{
private:
Inner *array_; //通常具有参考语义。
public:
Value() : array_(new Inner[NUM_INNER]){}
~Value() {delete[] array_;}
Value(const Value &val) : array_(new Inner[NUM_INNER])
{
for(int i = 0; i < NUM_INNER; ++i)
array_[i] = val.array_[i];
}
Value &operator=(const Value &val)
{
for(int i = 0; i < NUM_INNER; ++i)
array_[i] = val.array_[i];
return *this;
}
};移动语义允许一种类型,Value以避免真正复制其引用数据。如果用户以引起移动的方式使用该值,则可以将“复制”自对象的数据保留为空:
struct Inner {int i;};
constexpr auto NUM_INNER = 5;
class Value
{
private:
Inner *array_; //通常具有参考语义。
public:
Value() : array_(new Inner[NUM_INNER]){}
//单击确定以删除,即使nullptr
~Value() {delete[] array_;}
Value(const Value &val) : array_(new Inner[NUM_INNER])
{
for(int i = 0; i < NUM_INNER; ++i)
array_[i] = val.array_[i];
}
Value &operator=(const Value &val)
{
for(int i = 0; i < NUM_INNER; ++i)
array_[i] = val.array_[i];
return *this;
}
//移动意味着没有内存分配。
//无法引发异常。
Value(Value &&val) noexcept : array_(val.array_)
{
//我们窃取了旧的价值。
val.array_= nullptr;
}
//无法引发异常。
Value &operator=(Value &&val) noexcept
{
//聪明的把戏。由于无论如何val将很快被销毁,
//我们与我们交换他的数据。他的破坏者将破坏我们的数据。
std::swap(array_, val.array_);
}
};的确,如果我们想禁止深层复制同时仍允许对象移动,那么我们甚至可以使这种类型不可复制。
struct Inner {int i;};
constexpr auto NUM_INNER = 5;
class Value
{
private:
Inner *array_; //通常具有参考语义。
public:
Value() : array_(new Inner[NUM_INNER]){}
//单击确定以删除,即使nullptr
~Value() {delete[] array_;}
Value(const Value &val) = delete;
Value &operator=(const Value &val) = delete;
//移动意味着没有内存分配。
//无法引发异常。
Value(Value &&val) noexcept : array_(val.array_)
{
//我们窃取了旧的价值。
val.array_= nullptr;
}
//无法引发异常。
Value &operator=(Value &&val) noexcept
{
//聪明的把戏。由于无论如何val将很快被销毁,
//我们与我们交换他的数据。他的破坏者将破坏我们的数据。
std::swap(array_, val.array_);
}
};我们甚至可以通过使用来应用零规则unique_ptr:
struct Inner {int i;};
constexpr auto NUM_INNER = 5;
class Value
{
private:
unique_ptr<Inner []>array_; //仅移动类型。
public:
Value() : array_(new Inner[NUM_INNER]){}
//无需显式删除。甚至声明。
~Value() = default; {delete[] array_;}
//无需显式删除。甚至声明。
Value(const Value &val) = default;
Value &operator=(const Value &val) = default;
//将执行逐元素移动。
Value(Value &&val) noexcept = default;
//将执行逐元素移动。
Value &operator=(Value &&val) noexcept = default;
};