2

Nicolai Josuttis, in his book "The C++ Standard Library - A Tutorial and Reference", writes, at page 44, the following paragraph :

According to the concept of auto_ptrs, it is possible to transfer ownership into a function by using a constant reference. This is very dangerous because people usually expect that an object won't get modified when you pass it as a constant reference. Fortunately, there was a late design decision that made auto_ptrs less dangerous. By some tricky implementation techniques, transfer of ownership is not possible with constant references. In fact, you can't change the ownership of any constant auto_ptr: …

If is not possible to change ownership with a constant reference, why the expressions "This is very dangerous" and "less dangerous" above ?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Belloc
  • 6,318
  • 3
  • 22
  • 52
  • He was describing the scenario _before_ they made it not possible to change ownership with a const reference. – ildjarn Feb 21 '12 at 17:00
  • @ildjarn But what about this sentence "Fortunately, there was a late design decision that made auto_ptrs **less dangerous**". – Belloc Feb 21 '12 at 17:03
  • Right, they made it not possible to change ownership with a const reference -- you're asking why _that_ is less dangerous? – ildjarn Feb 21 '12 at 17:04
  • 1
    My native tongue is not english. But I presume there is nothing dangerous in this case. So why the expression "less dangerous" ? – Belloc Feb 21 '12 at 17:06
  • 1
    The fact that the copy constructor (which takes a non-const reference) can transfer ownership at all is still dangerous, just not as dangerous as if the copy constructor took a const reference. This is why `std::auto_ptr<>` has been frowned on for years (with `boost::scoped_ptr<>` and `boost::shared_ptr<>` taking supremacy of the C++03 smart pointers) and is now _officially_ deprecated in C++11 in favor of `std::unique_ptr<>`. – ildjarn Feb 21 '12 at 17:08
  • @ildjarn I'm still trying to learn auto_ptr ... – Belloc Feb 21 '12 at 17:13
  • Don't bother! It's error-prone to the point of being broken. If you're using C++11 then learn `std::unique_ptr<>`; otherwise, look at the [Boost.SmartPtr](http://www.boost.org/libs/smart_ptr/) classes. :-] – ildjarn Feb 21 '12 at 17:21

1 Answers1

5

Summing up comments:

"This is very dangerous" refers to when std::auto_ptr<>'s copy constructor (which transfers ownership) took a const reference argument – this is a complete violation of const-correctness.

"Less dangerous" refers to the fact that the copy constructor (which now takes a non-const reference) can transfer ownership at all; this is still dangerous, just not as dangerous as when the copy constructor took a const reference.

This aspect of std::auto_ptr<> is universally considered a flaw in the class, to the extent that it's generally considered unusably broken. Consequently, boost::scoped_ptr<> and boost::shared_ptr<> are largely considered the "real" smart pointers of C++03, and in C++11 std::auto_ptr<> is deprecated altogether in favor of std::unique_ptr<> (and removed entirely in C++17).


Update: As of Boost 1.57, the Boost.Move library now supplies a C++03 emulation of std::unique_ptr<> which should be used rather than boost::scoped_ptr<>: boost::movelib::unique_ptr<>.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • 1
    "This aspect of `std::auto_ptr<>` is universally considered a flaw in the class": I disagree. It is fine as long as you know what you're doing. Without move semantics, it is *impossible* to return a non-reference-counted smart pointer from a function. `std::auto_ptr<>` gets around that problem. Yes, it breaks the concept of "copy" to do so, but that's what the language provided, so that was the only alternative. If you've got access to `unique_ptr` then obviously you should drop `auto_ptr`. But as long as you're aware how it behaves, it's perfectly usable. – Nicol Bolas Feb 21 '12 at 17:29
  • @Nicol : The fact that its semantics are non-obvious (and contrary to the rest of the standard library) isn't a flaw? ;-] Error-prone trumps "usable" in my book -- it's hard to screw up usage of `std::shared_ptr<>` or `std::unique_ptr<>`, but it's very easy to screw up usage of `std::auto_ptr<>`. – ildjarn Feb 21 '12 at 17:31
  • Treating an auto_ptr as if it were a unique_ptr works for me, otherwise I try to avoid it. – Mark Ransom Feb 21 '12 at 17:31
  • This aspect of `auto_ptr` is generally considered a positive aspect, and is a major motivation for using `auto_ptr`. It has been carried over to `unique_ptr`. The reason `auto_ptr` was deprecated was simply that it was too complicated, and over specified; for the normal user, `unique_ptr` replaces it in all aspects. – James Kanze Feb 21 '12 at 17:37
  • @James : Absolutely not -- `std::unique_ptr<>` is not copyable, only movable, which is exactly what makes it an improvement on `std::auto_ptr<>` (plus C-array support, which makes it much _more_ complicated than `std::auto_ptr<>`, implementation-wise). – ildjarn Feb 21 '12 at 17:39
  • @MarkRansom And what cases would those be? (I use `auto_ptr` rather regularly---much more than `shared_ptr`, which _is_ dangerous. I expect that I'll be able to replace it systematically with `unique_ptr` once I don't have to support older compilers.) – James Kanze Feb 21 '12 at 17:39
  • @ildjarn "... just not as dangerous as when the copy constructor took a const reference". I didn't understand this. If the copy constructor used to take a constant reference, how was it possible to transfer the object's ownership ? – Belloc Feb 21 '12 at 17:46
  • @user1042389 : According to proper const-correctness, it shouldn't be possible -- that's the whole point. (Implementation-wise, `mutable` was probably involved.) – ildjarn Feb 21 '12 at 17:48
  • @ildjarn I thought that `mutable` affected only constant member functions, not const reference arguments. – Belloc Feb 21 '12 at 17:51
  • @user1042389 : It affects data members as well; data members on a const object are implicitly const unless they're explicitly marked `mutable`. – ildjarn Feb 21 '12 at 17:54
  • @ildjarn That was great. I didn't know about this aspect of `mutable`. I'm giving you the credit for the answer for this, although I believe the author's "less dangerous" has nothing to do with the copy constructor. Thanks anyway. – Belloc Feb 21 '12 at 18:03
  • @user1042389 : You can read the `std::unique_ptr<>` proposal, which deprecates `std::auto_ptr<>`, for the rationale on that deprecation -- it is absolutely related to the copy constructor being considered dangerous and counter-intuitive. – ildjarn Feb 21 '12 at 18:05
  • I wonder, then. If I can't pass a local variable of type `unique_ptr` to another object, `unique_ptr` looses a lot of its usefulness. The whole point of using `auto_ptr` is that when I pass it to an other object, I can no longer use it locally. (For example, if the other object is a message queue to another thread.) – James Kanze Feb 21 '12 at 18:14
  • 1
    @James : You can _move_ it to another object, but those semantics are obvious since they're usually explicit (i.e. you see a `std::move()`). – ildjarn Feb 21 '12 at 18:14