我正在尝试交换对象本身。它有效,但当我添加析构函数时,它会给我一个双自由错误。有办法防止这种情况发生吗?我说的方法是void swap(SimpleArray &object)
。
(很抱歉,如果你在我的帖子中有错误的信息之前读过这个…)
#include "TestType.h"
class SimpleArray {
private:
TestType* pArray;
//TestType* temp;
public:
SimpleArray(TestType *array)
{
this->pArray = array;
}
~SimpleArray() { delete[] pArray; }
SimpleArray() { pArray = 0;}
SimpleArray(const SimpleArray& arg){ pArray = arg.pArray; }
~SimpleArray() { delete[] pArray; }
TestType * get() const{ return pArray; }
bool isNonNull() const { return pArray != 0; }
//TestType* pArray;
void reset(TestType*& p) {this->pArray = p; }
void reset() { pArray = 0; }
void swap(SimpleArray &object) { SimpleArray temp; temp = object; object = *this; *this = temp;}
TestType * release() { pArray = 0; return pArray; }
TestType& getReference(int a) { return *pArray; }
};
这是有效的,但一旦我添加了析构函数,就会出现"双重自由或损坏错误"。我该如何解决此问题?这是一个主要的函数,它会出错。
bool testGetReleaseSwap() {
SimpleArray array1;
if (array1.get() != 0)
return false;
TestType* directArray1 = new TestType[100];
array1.reset(directArray1);
if (array1.get() != directArray1)
return false;
TestType* directArray2 = new TestType[50];
SimpleArray array2(directArray2);
array1.swap(array2);
if (array1.get() != directArray2 || array2.get() != directArray1)
return false;
array2.swap(array1);
if (array1.get() != directArray1 || array2.get() != directArray2)
return false;
array1.swap(array1);
if (array1.get() != directArray1)
return false;
if (array1.release() != directArray1 || array2.release() != directArray2)
return false;
if (array1.get() != 0 || array2.get() != 0)
return false;
delete[] directArray1;
delete[] directArray2;
return true;
}
这里的简单方法是在swap
方法的末尾调用temp.release()
,以防止双重删除。
然而,根本问题要深刻得多。在C++中,始终保持谁拥有某个东西的严格语义是至关重要的,例如需要删除的内存区域。
一种常见的模式是,分配某物的对象也负责清理,而不负责清理其他对象。这很适合SimpleArray
,但复制构造函数会破坏它,因为它会增加所有者的数量!
要实现共享数据语义,您必须投入更多的工作(引用计数等),或者必须禁止数组复制并使复制构造函数私有。
在不复制对象的情况下修复swap
工作的一种干净方法是:
void swap(SimpleArray &object) {
TestType* temp = object.pArray;
object.pArray = this->pArray;
this->pArray = temp;
}
(std::swap(object.pArray, pArray);
也起作用)
因为交换数组的内存区域非常适合单一所有者模式,所以这里出现的问题只是使用了完整的对象副本。
您应该阅读C++中的资源管理和所有权语义。您的代码总是容易出错的,除非您绝对知道谁拥有。
在我看来,您正试图实现一个具有浅复制语义(可能是写时复制)的类。要成功地做到这一点,您需要跟踪共享数据的其他所有者还有多少,并需要在该计数为零时销毁所拥有的对象。您可以为此使用std::shared_ptr
,也可以自己实现引用计数。
至于那个具体例子中的真正问题,看看复制构造函数在做什么。它不是复制,而是简单地对其参数已经拥有的对象进行另一个引用(一个特定的指针)。这本身就足以获得双倍免费,而您的swap
测试用例只是暴露了这个问题。