double free or corruption (runs ok if reorder lines)
在link中使用示例,但改为使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <vector> using namespace std; class Test{ char *myArray; public: Test(){ myArray = new char[10]; } ~Test(){ delete[] myArray; } }; int main(){ vector<Test> q; // line 1 Test t; // line 2 q.push_back(t); } |
它将导致双重自由或损坏错误。但是,如果在第1行之前运行第2行,例如:
1 2 | Test t; vector<Test> q; |
然后运行正常。为什么会这样?
在Xubuntu 12.04 G++4.6.3上测试。
更新:
这不是重复的问题。我知道需要一个复制构造函数和一个赋值运算符(上面的链接中已经回答了它,示例代码来自那里)。但是,使用
您的类型管理资源(动态分配的数组),但不实现三个规则。当你这样做的时候:
1 | q.push_back(t); |
您需要实现一个复制构造函数和一个分配运算符。或者使用管理自己资源的类,如
在已经删除的数组上调用
当
您应该指定一个复制构造函数并对对象进行深度复制。以及一个新的数组。
此外,还强烈建议使用重载赋值运算符(在与上面相同的链接中进行解释)。
这是因为当测试对象由向量管理时,以及当它们被推回插入时,测试对象会自动创建和删除。想象一下,当新元素添加到向量中时,需要和分配更多的空间,并将现有元素复制到新地址。这意味着它们被删除,动态内存被释放。为了能够克服这个问题,请为类定义复制构造函数,该构造函数将对对象进行深度复制。或者使用智能指针,如UnQuyJ-PTR或SysDypPTR(来自Boost或C++ 11)。
规则三(http://en.wikipedia.org/wiki/rule_of_3_28c%2b%2b_programming%29)。很可能在两个
因为您需要一个复制构造函数。
因此,您需要定义
1 2 3 4 5 6 7 8 | Test( const Test& other ) { // ... } Test& operator=( const Test& other ) // just in case { // ... } |
并进行深度复制,手动复制
*)导致双重删除——一次从EDOCX1的析构函数中删除,一次从EDOCX1的析构函数中删除(调用向量中所有元素的析构函数)。