auto_ptr作为最早的智能指针,可以实现以RAII手法管理堆区对象,但它设计的本意只是简单的利用C++对于栈区对象的自动析构管理堆区对象,

并不像shared_ptr那样包含引用计数,可以在每次拷贝的时候多出一个“分身”。这时候,拷贝的语义就成了很大的问题(按理说直接禁掉可能好好些),

于是就出现了下面这个不伦不类的原型:

explicit auto_ptr (X* p=0) throw();
auto_ptr (auto_ptr& a) throw();
template<class Y>
  auto_ptr (auto_ptr<Y>& a) throw();
auto_ptr (auto_ptr_ref<X> r) throw();
auto_ptr& operator= (auto_ptr& a) throw();
template <class Y>
  auto_ptr& operator= (auto_ptr<Y>& a) throw();
auto_ptr& operator= (auto_ptr_ref<X> r) throw();

这个跟一般我们定义一个类的拷贝(构造和赋值)函数就不一样了:

class foo
{
    foo(const foo& a);
   foo& operator=(const foo& a);
}

关键在于少了const,而每当auto_ptr被拷贝,它都会被置为null,相当于“移动”的语义。

这样不仅违反直觉,而且在C++11里有了正统的移动语义的情况下更显得奇怪,于是重新设计了unque_ptr

,改动不大,只是把语义纠正过来了,

default (1)    

constexpr unique_ptr() noexcept;

from null pointer (2)    

constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}

from pointer (3)    

explicit unique_ptr (pointer p) noexcept;

from pointer + lvalue deleter (4)    

unique_ptr (pointer p,
    typename conditional<is_reference<D>::value,D,const D&> del) noexcept;

from pointer + rvalue deleter (5)    

unique_ptr (pointer p,
    typename remove_reference<D>::type&& del) noexcept;

move (6)    

unique_ptr (unique_ptr&& x) noexcept;

move-cast (7)    

template <class U, class E>
  unique_ptr (unique_ptr<U,E>&& x) noexcept;

move from auto_ptr (8)    

template <class U>
  unique_ptr (auto_ptr<U>&& x) noexcept;

copy (deleted!) (9)    

unique_ptr (const unique_ptr&) = delete;

可以看到,拷贝操作直接被禁掉了。

在应用方面,auto_ptr由于奇怪的拷贝语义,导致在容器中使用的话很容易出错,比如下面的代码:

vector<auto_ptr<int>> foo;
...
auto  item = foo[0];

容器中的元素不知不觉就被改掉了(置为null)。

如果是unique_ptr,就看得很清楚了:

vector<unique_ptr<int>> foo;
...
auto  item = std::move(foo[0]);

这样也算是更改了容器,但是加上std::move之后(不加会错,因为拷贝被禁用了),代码的意图明显多了。