Unique ownership without move semantics std::auto_ptr
suggest changeNOTE: std::auto_ptr
has been deprecated in C++11 and will be removed in C++17. You should only use this if you are forced to use C++03 or earlier and are willing to be careful. It is recommended to move to unique_ptr in combination with std::move
to replace std::auto_ptr
behavior.
Before we had std::unique_ptr
, before we had move semantics, we had std::auto_ptr
. std::auto_ptr
provides unique ownership but transfers ownership upon copy.
As with all smart pointers, std::auto_ptr
automatically cleans up resources (see RAII):
{
std::auto_ptr<int> p(new int(42));
std::cout << *p;
} // p is deleted here, no memory leaked
but allows only one owner:
std::auto_ptr<X> px = ...;
std::auto_ptr<X> py = px;
// px is now empty
This allows to use std::auto_ptr to keep ownership explicit and unique at the danger of losing ownership unintended:
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
The transfer of ownership happened in the “copy” constructor. auto_ptr
’s copy constructor and copy assignment operator take their operands by non-const
reference so that they could be modified. An example implementation might be:
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 ... */
};
This breaks copy semantics, which require that copying an object leaves you with two equivalent versions of it. For any copyable type, T
, I should be able to write:
T a = ...;
T b(a);
assert(b == a);
But for auto_ptr
, this is not the case. As a result, it is not safe to put auto_ptr
s in containers.