简体   繁体   中英

Why unique_ptr works but auto_ptr doesn’t with STL

I have referred to lot of StackOverflow links on these questions where the reason for auto_ptr not working well with STL is std::auto_ptr<> does not fulfill the requirements of being copy-constructible and assignable (since auto_ptr has a fake copy constructor which basically transfers the ownership).

But even unique_ptr doesn't have copy ctor and assignment operator (it's disabled), so how is the requirement of being copy-constructible and assignable fulfilled?

You're looking at the whole thing backwards.

In C++98/03, we got auto_ptr . This type lies to everyone by pretending that it supports copy semantics when in fact copying it does something very much unlike a copy operation. Therefore, any type which relies on a type providing copy semantics, like certain containers, would not take well to getting an auto_ptr . Of course, you will only find out when your code becomes dysfunctional, not at compile time.

In C++11, we got unique_ptr , a type which explicitly does not provide copy semantics. Instead, it provides move semantics, and provides them correctly. Therefore, any type which relies on a type providing copy semantics will fail to compile when given a unique_ptr .

However , the reason unique_ptr came into being at all because the concept of moving an object was added to the language in C++11. When new concepts get added to the language, existing tools, like standard library requirements, are often re-evaluated relative to that language feature.

For example, types that formerly required copy semantics did not necessarily have to keep that requirement. C++98/03 containers that required copy semantics were updated in C++11 to only require (noexcept) move semantics from a type.

So it's not that unique_ptr fulfills some requirement that auto_ptr did not. It's that the language changed to no longer need that requirement, but auto_ptr was still lying about what it did, so for backwards compatibility sake, we created a new type that respected the new language features and didn't lie to people.

I assume you're referring to using smart pointers with STL containers.

auto_ptr can, but shouldn't be used because its copy constructor may accidentally move data (it was designed before move semantics with rvalue references were added in C++11).

unique_ptr doesn't have a copy constructor, so it can't be trivially used in STL containers. Operations that copy the pointer won't work, but that's what makes it safe. You can still explicitly use move iterators or emplace to get noncopyable elements into containers.

Examples for using unique_ptr in containers here: So can unique_ptr be used safely in stl collections?

auto_ptr looks like copy constructible / assignable, because it has a copy constructor and assignment operator.

The problem is that its copy constructor and assignment don't implement copy semantics, but move semantics instead. This makes the interface of auto_ptr surprising, and makes it unusable in containers that assign elements internally (such as vector).

What makes this worse is that using auto_ptr in a vector is well-formed (no compilation error), but doesn't have useful behaviour, which can easily lead to undefined behaviour (ie serious bugs).

But even unique_ptr doesn't have copy ctor and assignment operator(its disabled)

unique_ptr doesn't need to be copy constructible or assignable. It is sufficient to be move constructible and assignable for most use cases.

unique_ptr can replace all uses of auto_ptr, and doesn't have the problems of auto_ptr. Since C++11 where unique_ptr as well as language support for moving was introduced, auto_ptr has been deprecated and since C++17, auto_ptr has been removed from the standard library.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM