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

来源:互联网 发布:linux svn 删除仓库 编辑:程序博客网 时间:2024/05/16 11:56

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)代替指针,或者容器被析构时手工删除其中的每个指针。

              

1 0
原创粉丝点击