没有移动语义的独特所有权(auto ptr)

Version < C++ 11

注意: std::auto_ptr 已在 C++ 11 中弃用,将在 C++ 17 中删除。如果你被迫使用 C++ 03 或更早版本并且愿意小心,你应该只使用它。建议结合 std::move 移至 unique_ptr 以取代 std::auto_ptr 行为。

在我们使用 std::unique_ptr 之前,在我们移动语义之前,我们有了 std::auto_ptrstd::auto_ptr 提供独特的所有权,但在副本上转让所有权。

与所有智能指针一样,std::auto_ptr 会自动清理资源(参见 RAII ):

{
    std::auto_ptr<int> p(new int(42));
    std::cout << *p;
} // p is deleted here, no memory leaked

但只允许一个所有者:

std::auto_ptr<X> px = ...;
std::auto_ptr<X> py = px; 
  // px is now empty 

这允许使用 std::auto_ptr 来保持所有权的显式和唯一性,以免意外失去所有权:

void f(std::auto_ptr<X> ) {
    // assumes ownership of X
    // deletes it at end of scope
};

std::auto_ptr<X> px = ...;
f(px); // f acquires ownership of underlying X
       // px is now empty
px->foo(); // NPE!
// px.~auto_ptr() does NOT delete

所有权的转移发生在复制构造函数中。auto_ptr 的拷贝构造函数和拷贝赋值运算符通过非 const 引用获取它们的操作数,以便可以修改它们。示例实现可能是:

template <typename T>
class auto_ptr {
    T* ptr;
public:
    auto_ptr(auto_ptr& rhs)
    : ptr(rhs.release())
    { }

    auto_ptr& operator=(auto_ptr& rhs) {
        reset(rhs.release());
        return *this;
    }

    T* release() {
        T* tmp = ptr;
        ptr = nullptr;
        return tmp;
    }

    void reset(T* tmp = nullptr) {
        if (ptr != tmp) {
            delete ptr;
            ptr = tmp;
        }
    }

    /* other functions ... */
};

这打破了复制语义,这要求复制一个对象会留下两个相同版本的对象。对于任何可复制的类型,T,我应该能够写:

T a = ...;
T b(a);
assert(b == a);

但对于 auto_ptr 来说,情况并非如此。因此,将 auto_ptrs 放入容器中是不安全的。