不要把auto_ptr放入容器[VC/C++编程]
本文“不要把auto_ptr放入容器[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
本来没有打算自己翻译Effective STL的,怕影响人情面感:),只是发现有些条款在网络上找不到,只好自己翻译了.--Winter
率直的讲,这个条款不该加入本书,因为包含atuo_ptr的容器(COAPs)本来在STL中就是禁止的.就算你这么用了,编译器也不会编译你的代码.而尺度委员会也没有注释为什么不能这样.关于COAPs我应当什么都不用说的,因为你的编译器应当替你做好了一切工作,全部这种近似的代码都不该该被编译.
惋惜的是,很多程序员利用的STL版本并不回绝COAPS,更要命的是,很多程序员发现这个曾经非常简单直接用于削减内存泄露的自动指针常常伴随指针容器.因此固然STL大概并不支持,很多程序员还是去试牟利用COAPs.
我来说授COAPs到底有什么缺陷,以至于尺度委员会都明确禁止它.好了,即刻开始.我讲一个不足点,不用auto_ptr的相关知识,乃至不用任何STL容器的知识你都能懂得:COAPs不机动(portable).他们到底能怎样?C++尺度中就禁止它了,好一点的STL平台将都不答应它的存在,这些都是有缘由的,我会渐渐奉告你.当前的STL平台没有禁止COAPs,你会发现存在COAPs时,代码比从前越发不机动了.只要你很看中机动性(当然应当如此),你就应当回绝利用COAPs.
但是大概你并不关心机动性,假如真是这样,请答应我和睦的提醒你,就是拷贝atuo_ptr的独特的(也可以说成是奇特的)定义.
当你拷贝一个auto_ptr,被auto_ptr所指的对象的全部权已经转移到了新的auto_ptr中去了,原有的auto_ptr被设置为NULL.你理解的没有错:拷贝一个auto_ptr,将会改变auto_ptr本身的值.
auto_ptr<Widget> pw1 (new Widget); // pwl1points to a Widget
auto_ptr<Widget> pw2(pw1); // pw2 points to pw1's Widget;
// pw1 is set to NULL. (Ownership
// of the Widget is transferred
//from pw1 to pw2.)
pw1 = pw2; // pw1 now points to the Widget
// again; pw2 is set to NULL
这大概很风趣,但当然是不正常的,你作为一个STL的利用者,要你当心利用的缘由是,auto_ptr会招致一些莫名其妙的后果.举例来说,具体看看下面看似“清白无辜”的代码,这些代码先产生一个包含atuo_ptr<Widget>的vector,然后通过对比指向Widgets的指针来对vector举行排序:
bool widgetAPCompare(const auto_ptr<Widget>& lhs,
const auto_ptr<Widget>& rhs) {
return *lhs < *rhs; //for this example, assume that
} // operator< exists for Widgets
vector<auto_ptr<Widget> > widgets; // create a vector and then fill it
//with auto_ptrs to Widgets;
// remember that this should
//not compile!
sort(widgets.begin(), widgets.end(), // sort the vector
widgetAPCompare);
不管这些代码看起来有多么公道,这个运行后果必定是不公道的.最简单的,排序的时刻,widgets中会有一个大概多个auto_ptrs的值被改成NULL.vector本身的排序操作,却改变了容器本身的值.把这此中的原理弄懂得还是对比值得的,我们来推断一下:
它大概是因为sort算法的实现(一个公用的办法,并被证明过的),在快速排序算法历程中不得不利用一些暂时变量.我们并不关心快速排序算法的具体实现,但其基本概念是,排序一个容器中的元素,一定会有某个元素用来作为“pivot element”,然会递归对比一个元素比这个pivot element大于小于或等于举行排序.在排序内部,实现办法大概像这样:
template<class RandomAccesslterator, // this declaration for
class Compare> // sort is copied straight
void sort( RandomAccesslterator first, // out of the Standard
RandomAccesslterator last,
Compare comp)
{
// this typedef is described below
typedef typename iterator_traits<RandomAccesslterator>::value_type
ElementType;
RandomAccesslterator i;
… // make i point to the pivot element
ElementType pivotValue(*i); //copy the pivot element into a
// local temporary variable; see
//discussion below
… //do the rest of the sorting work
}
除非你常常阅读STL源代码,不然你大概对这样的代码感到惊骇,其实,这些并不真的那么坏.里面唯一简单迷惑的是 iterator_traits<RandomAccesslterator>::value_type的引用,那却恰是STL的经典办法,当排序的时刻,通过它来辨认迭代器传过来的对象.假如我们想利用iterator_traits<RandomAccesslterator>::value_type,在它之前必须写typename,因为这是一个依靠于模板参数的范例名称,在这里,是RandomAccesslterator.假如想理解更多关于typename的信息,返回第七页) 在上面代码中,那个惹起麻烦的语句就是这行:
ElementType pivotValue(*i);
因为它从被排序的范围中拷贝了一个元素到本地的暂时对象中,在我们的谈论中,这个元素是一个自动指针auto_ptr<Widget>,所以这个行动让被拷贝的那个auto_ptr的值变成了NULL,也就是在vector中的元素的值变成了NULL,并且当完毕pivotValue的定义域时,它又自动删除了它指向的Widget.假如此时让sort函数直接返回,vector容器的值已经发生了改变,至少又一个Widget的值被释放了.由于快速排序是一个递归算法,每次递归城市挑选pivot element,因此将会又好几个vector的元素被设置为NULL,同时会有好几个Widget对象被释放.
这是一个非常邋遢的陷阱,这也是为什么尺度委员会如此勤奋的工作以避免你不会掉入这个陷阱中.为了恭敬他们的工作,也为了你自己的好处,毫不要把auto_ptrs放入你的容器,乃至当你的STL平台答应你这么做,你也不要这么做.
假如你的目标是用一个包含smart pointer(智能指针)的容器,你还是幸运的.包含smart pointers的简单都可以很好的工作.条款50,描写了在哪儿你能找到和STL容器结合非常完善的smart pointer.只是你不该该把auto_ptr放入容器,而不是smart pointer!
以上是“不要把auto_ptr放入容器[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |