std::pair and class destructors
Possible Duplicate:
What is The Rule of Three?
我把我的问题缩小到以下非常简单的例子。
下面,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //my_class.h class my_class { public: int an_int; int *array; //constructors: my_class() { array = new int[2]; } my_class(int new_int) : an_int(new_int) { array = new int[2]; } //destructor: ~my_class() { delete[] array; } }; //end of my_class |
同时,在主.cpp中…
1 2 3 4 5 6 7 8 9 | //main.cpp int main(int argc, char* argv[]) { std::map<int, my_class> my_map; my_map.insert( std::make_pair<int, my_class> (1, my_class(71) ) ); return 0; } // end main |
编译正常,但这会生成以下运行时错误:
1 | *** glibc detected *** ./experimental_code: double free or corruption (fasttop): |
或者,使用Valgrind:
1 2 3 4 5 6 | ==15258== Invalid free() / delete / delete[] / realloc() ==15258== at 0x40249D7: operator delete[](void*) (vg_replace_malloc.c:490) ==15258== by 0x8048B99: main (my_class.h:38) ==15258== Address 0x42d6028 is 0 bytes inside a block of size 8 free'd ==15258== at 0x40249D7: operator delete[](void*) (vg_replace_malloc.c:490) ==15258== by 0x8048B91: main (my_class.h:38) |
(因为我删掉了评论和内容,所以行号被取消)
我一定是错过了一些关于EDOCX1的东西。
感谢所有人的事先准备!
将
请看三条规则
在C++ 11中,如果你担心效率,也可以看看移动构造函数。
类违反了三条规则,定义了一个不带复制构造函数和赋值运算符的析构函数。一旦定义了这些,代码就可以正常运行了:STL容器严重依赖于这些,所以您应该问问自己,在每次使用类作为STL容器的模板参数时,是否都实现了这三个参数。
三人法则是幻想。标准的容器通常更漂亮。
问题是没有复制数组,而是复制指向数组的指针。现在,如果两个实例具有相同的指针,则将删除同一个数组两次。
可以为类定义适当的复制操作,但通常使用标准容器可以解决复制、获取内存、释放内存、自我分配和异常保证等所有问题。
- 使用
std::vector 作为动态阵列的替代品。 - 使用
std::array 作为固定大小阵列的替代品。
如果您的所有成员都有适当的复制语义,那么您的类甚至不需要显式的复制操作,因此您可以节省大量的工作,增加可维护性,并减少错误的几率。
所以:
一般来说,与手动数组相比,首选标准容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class my_class { public: my_class() : new_int(0), array(2) {} my_class(int new_int) : an_int(new_int), array(2) {} private: int an_int; std::vector<int> array; // do not expose them }; |
或
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class my_class { public: my_class() : new_int(0) {} my_class(int new_int) : an_int(new_int) {} private: int an_int; std::array<int,2> array; // do not expose them }; |
如果您必须省略标准容器:
- 编写一个复制构造函数。
- 编写副本分配。或
- 完全禁止复制。
BUF在这样做之前,阅读关于三的规则,注意自我分配的危险,知道交换技巧(注意:这是一个常见的C++习语),并且学习异常安全性(注意:你会在GOTW系列文章中找到很多免费的内容)。
您必须定义一个合适的复制构造函数,因为类的副本通过复制指针的实例共享相同的数组。