让我们假设以下场景。我有一个隐含的共享类,定义如下:
class MyClass
{
public:
MyClass (void) {
data = new Data();
data->refs = 1;
data->dummy = 32;
}
~MyClass (void) {
if (--data->refs == 0)
delete data;
}
MyClass (const MyClass& c) {
++(data = c.data)->refs;
}
MyClass& operator = (const MyClass& c) {
++(data = c.data)->refs;
return *this;
}
private:
struct Data {
int refs;
int dummy;
} *data;
};
这个想法是,当复制此类时,会复制指向数据的内部指针,并且会增加对该数据的引用数。但是,请考虑以下事项:
int main (void)
{
MyClass c1;
c1 = MyClass();
c1 = MyClass();
return 0;
}
我的理解是MyClass有三个实例,只有最后一个实例被解除分配。如果是这种情况,我该怎么做才能避免这些情况并确保每个MyClass实例都得到清理?
答案 0 :(得分:3)
在赋值运算符中,您需要确保在用新值覆盖其值之前清除分配给对象的对象。毕竟,赋值的左侧已经引用了一个值。编写赋值运算符的最简单方法是利用现有的复制构造函数和析构函数,并使用函数swap()
来交换这两个对象:
MyClass& MyClass::operator = (MyClass c) {
this->swap(c);
return *this;
}
void MyClass::swap(MyClass& other) {
std::swap(this->data, other.data);
}
这样,值已经复制到值c
中,当前值与c
保持的值交换。当c
被销毁时,引用计数会根据需要递减。
请注意,std::share_ptr<T>
已使用相当奇特的机制引用计数:您可能希望使用标准类而不是自己编写。
答案 1 :(得分:2)
MyClass& operator = (const MyClass& c) {
++(data = c.data)->refs;
return *this;
}
这已经破了。在你破坏this.data
之前,你需要减少它的引用并在引用降为零时删除它。