copy构造以及operator=操作符,其实都是拷贝class的私有变量,例如以下Test类,拷贝的为成员变量mData指向的数据,以及mDataLen的值
class Test {
public:
Test &operator=(const Test ©);
private:
uint8_t *mData;
int mDataLen;
};
- 自然想到的实现方法:
Test &operator=(const Test ©) {
if(this.mData) {
free(this.mData);
}
this.mData = (uint8_t *)malloc(copy.mDataLen);
this.mDataLen = copy.mDataLen;
memcpy(mData, copy.mData, copy.mDataLen);
return *this;
}
- 上述1的实现可能出现对象自我赋值,修改为:
Test &operator=(const Test ©) {
if(this == ©) {
return *this;
}
if(this.mData) {
free(this.mData);
}
this.mData = (uint8_t *)malloc(copy.mDataLen);
if(this.mData == NULL) return *this;
this.mDataLen = copy.mDataLen;
memcpy(mData, copy.mData, copy.mDataLen);
return *this;
}
- 上述2的实现,在malloc的时候,可能出现异常,应确保没有资源泄漏,并尽量保持原状态,
修改为以下,在新内存创建成功情况下,再释放原内存,因此已经避免了自我赋值,因此可以将相关语句去掉:
Test &operator=(const Test ©) {
uint8_t *pOriData = this.mData;
this.mData = (uint8_t *)malloc(copy.mDataLen);
if(this.mData == NULL) return *this;
this.mDataLen = copy.mDataLen;
memcpy(mData, copy.mData, copy.mDataLen);
if(this.pOriData) {
free(this.pOriData);
}
return *this;
}
- 上述3的实现实际是 copy and swap技术,因此可以使用标准库函数swap,
首先std::swap保证了不会出现异常,其次swap操作对象,只是做指针的转换,效率更高,
但注意是拷贝,不能影响被拷贝者的值,因此只能使用被拷贝者的副本执行swap操作:
Test &operator=(const Test ©) {
Test temp(copy);
std::swap(*this, temp);
return *this;
}
- 还有一种实现,参数传值代替传引用,将“拷贝动作”由函数体移到了函数参数构造阶段,可能会另编译器生成更高效的代码,为operator=的接口一致性,还是建议使用4的实现:
Test &operator=(const Test copy) {
std::swap(*this, copy);
return *this;
}