条目八《永不建立auto_ptr的容器》
重要的事说三次,永不建立auto_ptr的容器,永不建立auto_ptr的容器,永不建立auto_ptr的容器!!!
为什么?
实质是auto_ptr
指针在转移时把原本的指针置为NULL,然而在STL容器中的一些操作是包含数据转移操作的。
比如排序sort(),在STL中,容器的sort的底层是基于多种排序算法的,其中的快排更是最重要的一种。快排的核心是每次递归选出一个基准值,然后把数据分为大小于基准值两部分,直至整个数据排列完成。
假如是auto_ptr
容器,在每次递归的时候,基准值会转移为NULL,并且这个基准值局部变量在当前递归结束时会被销毁,因此会发生整个快排下来,整个数据会有几个数值是缺少的和为NULL的,这些数据都是每次递归选出来的基准值。
请看stl源码:
bool 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); 这是一个vector的sort例子。
template<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); //把基准值复制到局部临时变量中
...
}
这里的重点的这一句ElementType pivotValue(*i);
,解释直接参考书的:
它把一个元素从保存的区间拷贝到局部临时对象中。在我们的例子里,这个元素是一个auto_ptr
,所以这个拷贝操作默默地把被拷贝的auto_ptr——vector中的那个——设为NULL。另外,当pivotValue出了生存期,它会自动删除指向的Widget。这时sort调用返回了,vector的内容已经改变了,而且至少一个Widget已经被删除了。
其实这个很容易理解,就是因为是auto_ptr容器,如果调用容器的操作涉及到容器元素转移的会造成把容器原数据的置为NULL,并且元素会被删除,删除个数是递归的个数。