105

I heard auto_ptr is being deprecated in C++11. What is the reason for this?

Also I would like to know the difference between auto_ptr and shared_ptr.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
brett
  • 5,379
  • 12
  • 43
  • 48
  • Possible duplicate of [Is auto\_ptr deprecated?](http://stackoverflow.com/questions/2404115/is-auto-ptr-deprecated) – malat Aug 16 '16 at 10:18

5 Answers5

100

The direct replacement for auto_ptr (or the closest thing to one anyway) is unique_ptr. As far as the "problem" goes, it's pretty simple: auto_ptr transfers ownership when it's assigned. unique_ptr also transfers ownership, but thanks to codification of move semantics and the magic of rvalue references, it can do so considerably more naturally. It also "fits" with the rest of the standard library considerably better (though, in fairness, some of that is thanks to the rest of the library changing to accommodate move semantics instead of always requiring copying).

The change in name is also (IMO) a welcome one -- auto_ptr doesn't really tell you much about what it attempts to automate, whereas unique_ptr is a fairly reasonable (if terse) description of what's provided.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 26
    Just a note on the `auto_ptr` name: auto suggests automatic as in automatic variable, and it refers to one thing that `auto_ptr` do: destroy the managed resource in its destructor (when it goes out of scope). – Vincenzo Pii Feb 05 '12 at 19:09
  • 18
    Further information: Here is the official rationale for deprecating `auto_ptr`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.4.5%20-%20Class%20template%20auto_ptr – Howard Hinnant Apr 18 '14 at 14:34
  • @HowardHinnant interesting doc! it is strange in a sense that if std::sort() is has a specialization for std::unique_ptr to use the move semantic as needed. I wonder why std::sort() can't be specialized for std::auto_ptr to correct the copy issue mentioned in the doc. Thanks in advance. – Hei Nov 15 '17 at 07:10
  • 2
    @Hei: `std::sort` doesn't have a specialization for `unique_ptr`. Instead it was re-specified to never copy. So `auto_ptr` actually *does* work with the modern `sort`. But the C++98/03 `sort` is just an example algorithm here: *Any* generic algorithm (std-supplied or user-written) that assumes that copy syntax has copy semantics will likely have a run-time error if used with `auto_ptr`, because `auto_ptr` silently *moves* with *copy* syntax. The issue is **much** larger than just `sort`. – Howard Hinnant Nov 15 '17 at 14:10
37

I found the existing answers great, but from the PoV of the pointers. IMO, an ideal answer should have the user/programmer's perspective answer.

First thing first (as pointed by Jerry Coffin in his answer)

  • auto_ptr could be replaced by shared_ptr or unique_ptr depending upon situation

shared_ptr : If you are concerned about freeing of resource/memory AND if you have more than one function that could be using the object AT-DIFFERENT times, then go with shared_ptr.

By DIFFERENT-Times, think of a situation where the object-ptr is stored in multiple data-structure and later accessed. Multiple threads, of course is another example.

unique_ptr : If all you are concerned is freeing memory, and the access to object is SEQUENTIAL, then go for unique_ptr.

By SEQUENTIAL, I mean, at any point object will be accessed from one context. E.g. a object that was created, and used immediately after creation by the creator. After creation the object is stored in FIRST data-structure. Then either the object is destroyed after the ONE data-structure or is moved to SECOND data-structure.

From this line, I will refer shared/unique _ptr as smart-pointers. (auto_ptr is also smart-pointer BUT because of flaws in it's design,for which they are being deprecated, and which I think I will point out in next lines, they should not be grouped with smart-pointer. )

Single most important reason as to why auto_ptr was deprecated in favor of smart-pointer is assignment-semantics If it wasn't for that reason, they would have added all the new goodies of move semantics to the auto_ptr instead of deprecating it. Since the assignment-semantics was most-disliked feature, they wanted that feature to go away, but since there is code written that uses that semantics, (which standards-committee can not change), they had to let go of auto_ptr, instead of modifying it.

From the link : http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Kind of assignments supported by unqiue_ptr

  • move assignment (1)
  • assign null pointer (2)
  • type-cast assignment (3)
  • copy assignment (deleted!) (4)

From : http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

Kind of assignments supported by auto_ptr

  • copy assignment (4) culprit

Now coming to the reason WHY the copy assignment itself was so disliked, I have this theory :

  1. Not all programmers read books or standards
  2. auto_ptr on the face of it, promises you ownership of the object
  3. the little-* (pun intended), clause of the auto_ptr, which is not read by all the programmers, allows, assignment of one auto_ptr to another, and transfers the ownership.
  4. Research has shown this behavior is intended for 3.1415926535 % of all usage, and unintended in other cases.

The unintended behavior is really disliked and hence the dislike for the auto_ptr.

(For the 3.1415926536% of programmers who intentionally wants to transfer the ownership C++11 gave them std::move(), which made their intention crystal clear for all the interns who are going to read and maintain the code.)

hochl
  • 12,524
  • 10
  • 53
  • 87
Ajeet Ganga
  • 8,353
  • 10
  • 56
  • 79
  • 1
    Since you **never** want two `auto_ptr` values pointing to the same object (since they don't give shared ownership, the first one to die will leave the other with a lethal heritage; this is also true for `unique_ptr` usage) , can you suggest _what was_ intended in those remaining 96.8584073465% of all usage? – Marc van Leeuwen Jun 19 '14 at 04:49
  • Can't speak for the all of them, but I would guess, they would *think* the object ownership is being *moved* and NOT just duplicated, which is erroneous. – Ajeet Ganga Sep 22 '14 at 19:47
  • @AjeetGanga In the following phrase 'the little-* (pun intended),' you mentioned as "pun intended". This phrase is new for me and anyhow I googled it and got to know that there is some joke that was purposefully done here. What is that joke here? Just curious to know that. – VINOTH ENERGETIC May 05 '17 at 04:43
  • @AjeetGanga You mentioned like 'the little-* (pun intended), clause of the auto_ptr, which is not read by all the programmers, allows, assignment of one auto_ptr to another, and transfers the ownership'. Let say I have two auto ptr's as a and b to integer. I am doing the assignment as `*a=*b;` Here only value of b is copied to a. I Hope Ownership of both a and b is still with the same people. You mentioned like owenership will be transferred. How it will be? – VINOTH ENERGETIC May 05 '17 at 04:49
  • @VINOTHENERGETIC Ajeet was talking about assigning to an `auto_ptr` object itself. Assigning to/from its pointed-to value has no effect upon, nor relevance to, ownership. I hope you are not still using `auto_ptr`? – underscore_d Jun 04 '17 at 14:28
  • @underscore_d Got it. No am not using the shared pointer now. Just a curiosity to understand the concept – VINOTH ENERGETIC Jun 06 '17 at 10:13
  • it is not so much about unintended moves when "copying" an autopointer due to not reading the docs. The problem is rather that generic code runs into problems when something that looks like a copy is in fact a move. Library implementers do read books and the standard, but still there was no reasonable way to deal with `auto_ptr` once it is inside a container – 463035818_is_not_an_ai Sep 13 '18 at 13:08
  • What if you are not concerned about ownership, and only care about ensuring cleanup and code that compiles cleanly in C++03 and C++11 (and onwards). – jww Dec 16 '19 at 01:33
24

shared_ptr can be stored inside containers. auto_ptr can't.

BTW unique_ptr is really the direct auto_ptr replacement, it combines the best features of both std::auto_ptr and boost::scoped_ptr.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
13

Yet another take on explaining the difference....

Functionally, C++11's std::unique_ptr is the "fixed" std::auto_ptr: both of them are suitable when - at any point in time during execution - there should be a single smart-pointer owner for a pointed-to object.

The crucial difference is in copy-construction or assignment from another un-expiring smart pointer, shown on the => lines below:

   std::auto_ptr<T> ap(new T{...});       // OK - alloc/construct, up owns
   ...or...
   std::auto_ptr<T> ap(get_ap_to_T());   // OK - take expiring ownership

   ...then...
=> std::auto_ptr<T> ap2(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... tried to use ap, expecting it to be non-NULL

   // --------------------------------------------------------------

   std::unique_ptr<T> up(new T{...});       // OK - alloc/construct, up owns
   ...or...
   std::unique_ptr<T> up = std::make_unique<T>(...);       // OK too
   ...or...
   std::unique_ptr<T> up(get_up_to_T());   // OK - take expiring ownership

   ...then...
=> std::unique_ptr<T> up2(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up2(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up2(up.release());   // EXPLICIT code allowed

Above, the ap3 auto_ptr quietly "steals" ownership of *ap, leaving ap set to a nullptr, and the problem is that can happen too easily, without the programmer having thought through its safety.

For example, if a class/struct has a std::auto_ptr member, then making a copy of an instance will release the pointer from the instance being copied: that's weird and dangerously confusing semantics as usually copying something doesn't modify it. It's easy for the class/struct author to overlook the release of the pointer when reasoning about invariants and state, and consequently accidentally attempt to dereference smart-pointer while null, or just not still have expected access/ownership of the pointed-to data.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
5

auto_ptr cannot be used in STL containers because it has a copy constructor that does not meet requirements of container CopyConstructible. unique_ptr does not implement a copy constructor, so containers use alternate methods. unique_ptr can be used in containers and is faster for std algorithms than shared_ptr.

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3
Kapil
  • 362
  • 6
  • 7
JayS
  • 2,057
  • 24
  • 16