使用std::vector 的陷阱

容器里面都应该只存储简单数据结构,一旦数据结构为复杂数据结构时,则应该存储该数据的指针。

------------------------------------------------------------------------

内容摘要 因为vector不象list,vector始终要保持一个完整的内存结构(因为就是一个数组),这样才可以让values[1]这样的方式正确运行. 但是,如果要在vector中间删掉一个成员的话,vector是这样做的, 先把该成员后面的一个成员,一直到最后一个成员往前一位置拷贝,这样需要删除的成员已经被后面的覆盖了, 然后再删除最后一个成员,这样,vector又能保持一段完整的内存结构了


在使用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比较简便.

# re: 使用std::vector 的陷阱[未登录]  回复  更多评论  

其实我觉得这不是vector给你设的“陷阱”,STL容器只有责任维护你给他的东西,但没理由维护这个东西里面的东西。不仅仅是vector,STL所有的容器如果按你这种思维去用,都会出问题:
class Test
{
int *a;
~Test()
{
delete a;
}
};
std::vector<Test> 维护Test::a其实应该是你的责任。

剩余内容,参见http://www.cppblog.com/woaidongmao/archive/2011/12/03/95146.html

你可能感兴趣的:(使用std::vector 的陷阱)