The problem with auto_ptr
is that it can be copied and making a copy modifies the original:
a = b; // transfers ownership from b to a
This is similar to what moving does now, just that at the time of auto_ptr
there was no move semantics in the language. Now that C++ has move semantics transfer of ownership can be expressed more clearly:
a = std::move(b);
Nobody would/should expect that b
is not modified in that line.
However, with a = b
it is commonly assumed, that b
is not modified. auto_ptr
breaks that assumption. Consider for example:
template <typename P>
void foo() {
std::vector<P> x;
x.resize(42);
int i=0;
for (auto& e : x) e.reset(new int(i++));
for (auto e : x) {
std::cout << *e << "\n";
}
for (auto e : x) {
std::cout << *e << "\n";
}
}
With P=std::unique_ptr<int>
this will cause a compiler error:
<source>:17:15: error: call to deleted constructor of 'std::unique_ptr<int, std::default_delete<int> >'
for (auto e : x) {
^ ~
While it compiles with P=std::auto_ptr<int>
but is undefined behavior (eg segfault here: https://godbolt.org/z/93hdse), because it dereferences null pointers.
Similar issue with any algorithm assumes it is "ok" to copy elements. For example a comparator for auto_ptr
that takes parameters by value does compile but causes havoc:
auto compare = [](auto a,auto b) { return *a < *b; }
std::sort(x.begin(), x.end(),compare); // BOOM !
Not always is it so obvious that a copy is being made, algorithms may copy elements internally when elements are copyable.