首页 > 代码库 > Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉

Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉

STL中的容器相当“聪明”,它们提供了迭代器,以便进行向后和向前的遍历(通过begin、end、rbegin等);它们告诉你所包含的元素类型(通过它们的value_type类型定义);在插入和删除的过程中,它们自己进行必要的内存管理;它们报告自己有多少对象,最多能容纳多少对象(分别通过size和max_size);当然,当它们自身被析构时,它们自动析构所包含的每个对象。

       有了这么“聪明”的容器,许多程序员不再考虑自己做善后清理工作。更糟糕的是,他们认为,容器会考虑为他们做这些事情。很多情况下,他们是对的。但当容器包含的是new的方式而分配的指针时,他们这么想就不正确了。没错,指针容器在自己被析构时会析构所包含的每个元素,但指针的“析构函数”不做任何事情!它当然也不会调用delete。

       结果,下面的代码直接导致资源泄露:

       void doSomething()
       {
             vector<Widget*>vwp;
              for (int I = 0; I < SOME_MAGIC_NUMBER; ++i)
              {
                     Vwp.push_back(new Widget);
                     …
              }                                                //在这里发生了Widget资源泄露
       }


当vwp的作用域结束时,它的元素全部被析构,但并没有改变通过new创建的对象没有被删除这一事实。删除这些对象是你的责任,不是vector的责任。这是vector的特性。只有你才知道这些指针是否应该被释放。

	void doSomething()
	{
		for (vector<Widget*>::iterator I = vwp.begin(); i != vwp.end(); ++i)
			delete *i;
	}



这样做能行,但只是在你对“能行“不那么挑剔时。一个问题是,新的for循环做的事情和for_each相同,但不如使用for_each看起来那么清楚。问题是,这段代码不是异常安全的。如果在想vwp中填充指针和从中删除指针的两个过程中间有异常抛出的话,同样会有资源泄露。

其一解决方法如下:

       struct DeleteObject
       {
              template<typename T>
              void operator() (const T* ptr) const
              {
                     delete ptr;
              }
       };
       void doSomething()
       {
              deque<SpecialString*> dssp;
              for_each (dssp.begin(), dssp.end(), DeleteObject());
       }

但它仍然不是异常安全的。如果在SpecialString已经被创建而对for_each的调用还没开始时就有异常被抛出,则会有资源泄露发生。

 

其二解决方法:

利用Boost库中的shared_ptr。

       void doSomething()
       {
              typedef boost::shared_ptr<Widget> SPW;   //SPW= “指向Widget的shared_ptr”
              vector<SPW> vwp;
              for (int I = 0; I < SOME_MAGIC_NUMBER; ++i)
                     vwp.push_back(SPW(new Widget));
                     …
       }      //这里不会有Widget泄露,即使在上面的代码中有异常被抛出

 

永远不要错误的认为:你可以通过创建auto_ptr的容器使指针被自动删除。这个想法很危险,具体解释请看Effective STL 第8条。

 

       你要记住的是:STL容器很智能,但没有智能到知道是否该删除自己所包含的指针的程度。当你使用指针的容器,而其中的指针应该被删除时,为了避免资源泄露,你必须或者用引用计数形式的智能指针对象(比如Boost的shared_ptr)代替指针,或者容器被析构时手工删除其中的每个指针。

              

Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉