在使用std的容器的时候,不少人喜欢用vector, 因为比起list,更省空间,而且可以根据index直接读取某个值,而不用一个个枚举来取.
但是,std::vector确实有一些值得注意的陷阱, 这里先说其中一个, 请看以下代码.
std::vector< int > values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.erase(values.begin() + 1);
乍看之下,这几行简单的代码没什么 问题. 实际执行起来, 还是没什么问题 , 但却有一个陷阱. 由于例子里面用的是int的vector,所以这样做没有任何问题, 但,假如不是一个int, 而是一个类,一个结构体,类或结构体里面还有指针, 那就很可能出问题了. why?
因为vector不象list,vector始终要保持一个完整的内存结构(因为就是一个数组),这样才可以让values[1]这样的方式正确运行. 但是,如果要在vector中间删掉一个成员的话,vector是这样做的, 先把该成员后面的一个成员,一直到最后一个成员往前一位置拷贝,这样需要删除的成员已经被后面的覆盖了, 然后再删除最后一个成员,这样,vector又能保持一段完整的内存结构了. 注意,因为最后一个成员会被删除,而如果这个成员里面有一个成员变量是指针, 那析构函数很有可能会把这个指针指向的地方释放掉! 这样,即使最后一个成员被复制了一份 到倒数第2的位置,也因为在他本身被删除的时候,把倒数第2个(也就是它的复制) 的指针成员所指向的地方给释放了! 如图:
解决的办法也很简单, 最少有2种. 1, 增加作为vector类型的类的拷贝构造函数, 因为vector在erase的时候会发生一次拷贝,让拷贝构造函数不单单是复制指针,还把指针所指向的内容给拷贝一份,这样就不会导致被最后一个成员释放的时候一起释放掉了. 2, 如果有引用记数的话,如智能指针, 就不会被释放掉了。不过如果一般编码里面不需要用到引用记数的话,还是方法1比较简便.