Contain of auto_ptr (COAP)被禁止使用,其代码无法编译。原因很简单,COAP无法移植,再究其根本,在于auto_ptr被复制后,它所指向的对象的所有权被移交给lhs,而自身被置为nullptr,其特性可以用代码表述如下:1
2
3auto_ptr<Widget> pw1(new Widget); // pw1指向一个Widget
auto_ptr<Widget> pw2(pw1); // pw2指向pw1的Widget,pw1被设为nullptr
pw1 = pw2; // pw1现在再次指向Widget,pw2被设为nullptr
举一个COAP的例子,它建立一个包含auto_ptr<Widget>的vector,然后对这个vector内部元素排序,其排序指标是一个谓词:1
2
3
4
5bool widgetAPCompare(const auto_ptr<Widget>& lhs,const auto_ptr<Widget>& rhs) {
return *lhs < *rhs;
}
vector<auto_ptr<Widget> > widgets;
sort(widgets.begin(), widgets.end(),widgetAPCompare);//无法编译
这段代码看起来很合理,但实际上不行,原因在于在排序过程中widget中的一个或多个auto_ptr被置为null.之所以会这样,是快排的锅。快排的基本思想在于把容器内的某个元素作为pivot elements,然后对大于和小于等于该元素的其他元素递归调用排序。其方法看起来像这样:1
2
3
4
5
6
7
8template<class RandomAccessIterator,class Compare>
void sort(RandomAccessIterator first,RandomAccessIterator last,Compare comp){
typedef typename iterator_traits<RandomAccessIterator>::value_type ElementType;
RandomAccessIterator i;
... // 让i指向主元
ElementType pivotValue(*i);//将主元拷贝到一个局部变量中
...//接着排序
}
这个typename挺有讲究,强调了后面是一个类型,但我们不管,重点在于那个拷贝,它把auto_ptr的值放到了一个局部临时中,随着临时对象生命周期结束,对象也被析构了,真是倒了血霉。
所以说,不要搞包含auto_ptr的容器,其他智能指针配合容器倒是可以用用。