[c++11]复制和移动操作
参考:
Copy Constructors and Copy Assignment Operators (C++)
Move Constructors and Move Assignment Operators (C++)
复制和移动操作是c++11
新增的特性
- 复制指的是将一个对象的值复制给另一个对象
- 移动指的是将右值对象的资源通过移动方式(而不是复制)赋值给一个左值对象
每种操作最好同时实现构造器和运算符方式
复制构造器和复制赋值运算符
语法如下:
class Copy {
public:
// 声明复制构造器
Copy(const Copy &);
// 声明复制赋值构造器
Copy &operator=(const Copy &other);
};
设置参数为const
以避免操作过程中意外修改原对象的值
示例如下:创建类MemoryBlock
,设置字符数组_data
和数组长度_length
class MemoryBlock {
public:
// Simple constructor that initializes the resource.
MemoryBlock(int length, const char *data);
// Destructor.
~MemoryBlock();
// Copy constructor.
MemoryBlock(const MemoryBlock &other);
// Copy assignment operator.
MemoryBlock &operator=(const MemoryBlock &other);
// Retrieves the length of the data resource.
size_t Length() const;
// print _data
void print();
private:
size_t _length; // The length of the resource.
char *_data; // The resource.
};
创建了复制构造器和复制赋值构造器,实现如下:
MemoryBlock::MemoryBlock(int length, const char *data) {
_length = length;
_data = (char *) malloc(_length * sizeof(char));
std::copy(data, data + _length, _data);
std::cout << "In MemoryBlock: length = " << _length << " _data = " << _data << std::endl;
}
MemoryBlock::~MemoryBlock() {
std::cout << "In ~MemoryBlock(). length = " << _length << ".";
if (_data != nullptr) {
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
}
std::cout << std::endl;
}
MemoryBlock::MemoryBlock(const MemoryBlock &other) : _length(other._length), _data(new char[other._length]) {
std::cout << "In MemoryBlock(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
std::copy(other._data, other._data + _length, _data);
}
MemoryBlock &MemoryBlock::operator=(const MemoryBlock &other) {
std::cout << "In operator=(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
if (this != &other) {
// Free the existing resource.
delete[] _data;
_length = other._length;
_data = new char[_length];
std::copy(other._data, other._data + _length, _data);
}
return *this;
}
size_t MemoryBlock::Length() const {
return _length;
}
void MemoryBlock::print() {
std::cout << "Print MemoryBlock: length = " << _length << " _data = " << _data << std::endl;
}
使用函数std::copy
复制数组值
移动构造器和移动赋值运算符
移动操作用于将右值对象的内容移动到当前对象中,操作过程不需要复制,避免了额外的内存分配和解析操作,更加有效率
语法如下:
class Move {
public:
// 声明移动构造器
Move(Move &&);
// 声明移动赋值构造器
Move &operator=(Move &&other);
};
参数为Move
类型的右值引用,使用过程中去除const
关键字,能够修改参数对象的值以避免资源的重复释放
同上面一样,创建类MemoryBlock
,设置字符数组_data
和数组长度_length
class MemoryBlock2 {
public:
// Simple constructor that initializes the resource.
MemoryBlock2(int length, const char *data);
// Destructor.
~MemoryBlock2();
// Copy constructor.
MemoryBlock2(MemoryBlock2 &&other);
// Copy assignment operator.
MemoryBlock2 &operator=(MemoryBlock2 &&other);
// Retrieves the length of the data resource.
size_t Length() const;
// print _data
void print();
private:
size_t _length; // The length of the resource.
char *_data; // The resource.
};
实现如下:
MemoryBlock2::MemoryBlock2(int length, const char *data) {
_length = length, ;
_data = (char *) malloc(_length * sizeof(char));
std::copy(data, data + _length, _data);
std::cout << "In MemoryBlock2: length = " << _length << " _data = " << _data << std::endl;
}
MemoryBlock2::~MemoryBlock2() {
std::cout << "In ~MemoryBlock2(). length = " << _length << ".";
if (_data != nullptr) {
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
}
std::cout << std::endl;
}
MemoryBlock2::MemoryBlock2(MemoryBlock2 &&other) : _data(nullptr), _length(0) {
std::cout << "In MemoryBlock2(MemoryBlock2 &&). length = "
<< other._length << ". Moving resource." << std::endl;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
MemoryBlock2 &MemoryBlock2::operator=(MemoryBlock2 &&other) {
std::cout << "In operator=(MemoryBlock2 &&). length = "
<< other._length << "." << std::endl;
if (this != &other) {
// Free the existing resource.
delete[] _data;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
return *this;
}
size_t MemoryBlock2::Length() const {
return _length;
}
void MemoryBlock2::print() {
std::cout << "Print MemoryBlock2: length = " << _length << " _data = " << _data << std::endl;
}
移动操作如下:
- 释放当前对象的已有资源
- 复制移动对象的指针和长度
- 释放移动对象对资源的引用
- 对于移动赋值运算符而言,还应该考虑赋值操作是否指向自身
测试
在向量中插入对象时,移动操作能够提高性能,测试如下:
int main() {
// Create a vector object and add a few elements to it.
std::vector<MemoryBlock> v;
v.emplace_back(MemoryBlock(3, "123"));
v.emplace_back(MemoryBlock(5, "12345"));
// Insert a new element into the second position of the vector.
v.insert(v.begin() + 1, MemoryBlock(2, "45"));
更加有效率
// std::vector<MemoryBlock2> v2;
// v2.emplace_back(MemoryBlock2(3, "123"));
// v2.emplace_back(MemoryBlock2(5, "12345"));
//
// // Insert a new element into the second position of the vector.
// v2.insert(v2.begin() + 1, MemoryBlock2(2, "45"));
}
相比较于复制操作,移动操作不需要重新分配字符数组内存,更加有效率
优化
同时实现了移动构造器和移动赋值运算符后,可以在构造器中调用赋值运算符进行优化,使用函数std::move
修改如下:
// Move constructor.
MemoryBlock(MemoryBlock&& other): _data(nullptr), _length(0)
{
*this = std::move(other);
}