7.在析构前记得delete容器内通过new得到的指针

由于容器在析构时会自发地销毁所有容器内部的元素,因此有人会忽视容器内部元素的清除工作。大部分时候确实不用手动地清除,仅有一个例外:容器内存放的是通过new得到的指针。容器析构时指针当然被销毁了,但容器绝不会自动地调用delete释放每一个指针指向的对象,而且我们再也找不到这些对象了。

1
2
3
4
5
6
void doSomething(){
vector<Widget*> vwp;
for (int i = 0; i < SOME_MAGIC_NUMBER; ++i)
vwp.push_back(new Widget);
//vwp析构后资源也泄露了
}

delete这些指针并不麻烦,
1
2
3
4
5
void doSomething(){
vector<Widget*> vwp;
for (auto i = vwp.begin();i != vwp.end();++i)
delete *i;
}

上述代码看起来似乎很美好,但是仍然存在两点不存:

  1. 做了for_each做的事,但是不如for_each直观
  2. 不具备异常安全,如果在向vwp填充指针或者从中删除指针时有异常抛出,同样会内存泄漏。

首先解决第一个问题,将上述代码改写为for_each:

1
for_each(vwp.begin(),vwp.end(),[](Widget* pw){delete pw;});

(原书中描述了大量关于函数对象及其使用原理的说明,在C++11引入lambda之后,笔者跳过了这些知识)

使用shared_ptr可以避免异常安全的问题,我们通过将原容器替换为包含智能指针的容器之后,一切都变得美好了起来。