- 思路:
- 避免不必要的内存分配和释放:
- 对于动态分配的内存,如果源对象和目标对象可以共享这块内存,那么可以采用“拷贝指针,引用计数”的策略。这样在拷贝时,只是复制指针和增加引用计数,而不是重新分配内存。当对象析构时,如果引用计数为0才释放内存。
- 利用移动语义提高效率:
- 移动构造函数是为了在对象所有权转移时避免不必要的内存拷贝。当一个对象处于即将销毁的状态(如函数返回临时对象),可以将其资源“移动”到新对象,而不是复制。这意味着源对象的资源指针被转移到目标对象,源对象的指针被置为
nullptr
,从而避免了内存重新分配。
- 代码示例:
#include <iostream>
#include <memory>
class BigData {
private:
int* data;
std::size_t size;
std::size_t* refCount;
public:
// 构造函数
BigData(std::size_t s) : size(s) {
data = new int[size];
refCount = new std::size_t(1);
}
// 拷贝构造函数
BigData(const BigData& other) : size(other.size), data(other.data), refCount(other.refCount) {
(*refCount)++;
}
// 移动构造函数
BigData(BigData&& other) noexcept : size(other.size), data(other.data), refCount(other.refCount) {
other.data = nullptr;
other.refCount = nullptr;
other.size = 0;
}
// 析构函数
~BigData() {
if (refCount && --(*refCount) == 0) {
delete[] data;
delete refCount;
}
}
// 赋值运算符重载
BigData& operator=(const BigData& other) {
if (this == &other) {
return *this;
}
if (refCount && --(*refCount) == 0) {
delete[] data;
delete refCount;
}
size = other.size;
data = other.data;
refCount = other.refCount;
(*refCount)++;
return *this;
}
// 移动赋值运算符重载
BigData& operator=(BigData&& other) noexcept {
if (this == &other) {
return *this;
}
if (refCount && --(*refCount) == 0) {
delete[] data;
delete refCount;
}
size = other.size;
data = other.data;
refCount = other.refCount;
other.data = nullptr;
other.refCount = nullptr;
other.size = 0;
return *this;
}
};
class MyLargeClass {
private:
BigData bigData;
// 其他数据成员
public:
MyLargeClass(std::size_t s) : bigData(s) {}
// 拷贝构造函数利用BigData的拷贝构造优化
MyLargeClass(const MyLargeClass& other) : bigData(other.bigData) {
// 对于其他数据成员进行常规拷贝
}
// 移动构造函数利用BigData的移动构造优化
MyLargeClass(MyLargeClass&& other) noexcept : bigData(std::move(other.bigData)) {
// 对于其他数据成员进行常规移动(如果有的话)
}
};