19

I am learning about smart pointers (std::auto_ptr) and just read here and here that smart pointers (std::auto_ptr) should not be put in containers (i.e. std::vector) because even most compilers won't complain and it might seem correct. There is no rule that says smart pointers won't be copied internally (by vector class for example) and transfer its ownership, then the pointer will become NULL. In the end, everything will be screwed up.

In reality, how often does this happen?

Sometimes I have vectors of pointers and if in the future I decide I want to have a vector of smart pointers what would my options?

I am aware of C++0x and Boost libraries, but for now, I would prefer to stick to a STL approach.

Griwes
  • 8,163
  • 2
  • 39
  • 69
nacho4d
  • 39,335
  • 42
  • 151
  • 231
  • 2
    There are also smart pointers in std::tr1 (std::tr1::shared_ptr) – Martin York Jan 02 '11 at 10:04
  • 1
    I would not really call `auto_ptr` a smart pointer :) It's pretty dumb really, and therefore most advices about smart pointers cannot (unfortunately) be applied to it (because of its screwed copy semantics). – Matthieu M. Jan 02 '11 at 13:40

5 Answers5

16

Yes, you really can't use std::auto_ptr with standard containers. std::auto_ptr copies aren't equivalent, and because standard containers (and algorithms) are allowed to copy their elements at will this screws things up. That is, the operation of copying a std::auto_ptr has a meaning other than a mere copy of an object: it means transferring an ownership.

Your options are:

  1. Use the Boost Smart Pointers library. This is arguably your best option.
  2. Use primitive pointers. This is fast and safe, so long as you manage the pointers properly. At times this can be complex or difficult. For example, you'll have to cope with (avoid) double-delete issues on your own.
  3. Use your own reference-counting smart pointer. That'd be silly; use a Boost Smart Pointer.
wilhelmtell
  • 53,297
  • 19
  • 89
  • 128
  • 3
    Don't forget boost's `ptr_vector` and alike. – etarion Jan 02 '11 at 10:26
  • 8
    if you're o na compiler which supports it, `unique_ptr` is an option too. – jalf Jan 02 '11 at 10:32
  • 2
    I stongly disagree with the idea that `shared_ptr` is the best option. I see them as a last resort option, because shared ownership brings a lot of issues because of lifetime incertainty: yes the object will be alive as long as you need it, but it may also stay alive much longer than that, especially if you inadvertendly create a cycle of references... – Matthieu M. Jan 02 '11 at 13:42
  • I have been trying to stay away of non STL stuff up until but I see that many of the things I want to do are easily solved with boost libraries. I have been reading about boost::shared_ptr and boost::weak_ptr and I find them very useful, specially because of boost::shared_ptr is like having (in Objective-C) a property with retain attribute and boost::weak_ptr is like a property with assign attribute. Something that most C++ programmers probably are not used to. And indeed, it creates cycles if not used carefully. – nacho4d Jan 02 '11 at 14:40
  • @Matthieu @nacho4d I updated the text: use one of the smart pointers from Boost. I think the library covers for most of the most common cases, including that of cycles. But it's important to leave the mantra of "stick to STL". I was in this camp once too, a long time ago, and today I think it limits you, it hurts you more than it helps you. I think that if you have a standard C++ compiler and you don't have Boost then your C++ development environment is incomplete. Trust Boost more than your own code, and trust Boost is there. Your productivity and code quality will flourish. – wilhelmtell Jan 02 '11 at 18:01
  • From the future here - unique_ptr, shared_ptr, and weak_ptr have been incorporated into the standard library as of C++11. – 10762409 says Reinstate Monica Dec 27 '19 at 07:37
9

The problem you are referring to concerns auto_ptr since it moves ownership on copy. shared_ptr and unique_ptr work just fine with containers.

ronag
  • 43,567
  • 23
  • 113
  • 204
3

Any type that you use with a standard container template must conform with the requirements for that container. In particular, the type must satisfy the requirements for CopyConstructible and Assignable types.

Many smart pointers do satisfy these requirements and may be used with standard containers but std::auto_ptr is not one of them because copies of std::auto_ptr are not equivalent to the source that they were created or assigned from.

Although some implementations of standard container may work with auto_ptr in some situations it is dangerous to rely on such implementation details.

CB Bailey
  • 648,528
  • 94
  • 608
  • 638
2

theoretically you can use std::auto_ptr with STL containers if you completely understand their internal implementation and don't do anything that can lose auto_ptr ownership, but practically it's much more safe to use containers with raw ptrs.

"In reality, how often does this happen?" - is very dangerous question by itself. first of all, STL - it's not a single standard implementation, there're many. Each one can implement containers in different ways, so your highly tuned code to avoid all "auto_ptr in containers" mines can burst switching to another STL implementation. Also, your code maintenance will be highly complicated, any correctly looking change to your code can break your program. how can you remember that or force others maintainers to remember? putting warnings in any place where such changes can occur? impossible.

so, conclusion: it's just a bad idea that brings nothing but headache

Andriy Tylychko
  • 15,244
  • 5
  • 56
  • 103
  • Theoretically, and in many practical cases, `std::vector >` doesn't even compile. No matter of understanding can help you there, when the standard just forbids it. – MSalters Jan 03 '11 at 12:27
  • 1
    std::vector > compiles fine in VC9, isn't this standard-conformant behavior? – Andriy Tylychko Jan 03 '11 at 17:19
1

For classes that have an auto ptr data member, I always have a clone method that returns a new auto ptr. I then implement an assignment method and copy constructor that call the clone method (and never the default assignment operator of auto ptr). This way you can safely use the class in STL containers.

sbalian
  • 91
  • 6