4

This is the ctor used to construct a std::auto_ptr object from a standard pointer, in VS2008 compiler.

template<class _Ty>
class auto_ptr
{
   public:
   explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) {}

   private:
   _Ty *_Myptr;
};

Is there any particular reason why the explicit keyword is used above ?

In other words, why can't I initialize an auto_ptr with

std::auto_ptr<Class A> ptr = new Class A; ?

Ayrosa
  • 3,385
  • 1
  • 18
  • 29

4 Answers4

7

Becasue you could otherwise unintentionally do something like:

void foo(std::auto_ptr<int> p)
{
}

void boo()
{
    int* p = new int();
    foo(p);
    delete p; // oops a bug, p was implicitly converted into auto_ptr and deleted in foo.... confusing
}

In contrast with where you are actually explicitly aware of what is happening:

void boo()
{
    int* p = new int();
    foo(std::auto_ptr<int>(p)); // aha, p will be destroyed once foo is done.
}
ronag
  • 49,529
  • 25
  • 126
  • 221
  • @Victor Nicollet: Indeed I was thinking about whether to do it const ref or by value, and got stuck in between :P... – ronag Nov 17 '11 at 12:58
  • But this is also a bug : `void boo() { int* p = new int; foo(std::auto_ptr(p)); delete p; }` – Ayrosa Nov 17 '11 at 13:45
  • 2
    @Ayrosa: If you construct an `auto_ptr` explicitly and then try to delete the pointer, you deserve the bug. If the construction is implicit, you might just be unaware of what happened. – Gorpik Nov 17 '11 at 13:59
2

Constructing a std::auto_ptr is a transfer in ownership. It is best for everyone involved that transfers of ownership be kept explicit. For instance:

void frobnicate(const std::auto_ptr<Class> & ptr);

Class *instance = new Class();
frobnicate(instance);
delete instance;

If the constructor was implicit, then this code would compile, and it would be nearly impossible to notice that it was wrong without checking the definition of frobnicate. Besides, while using = for initialization is now harder, you can still use the other initialization syntax:

std::auto_ptr<Class> instance(new Class);
frobnicate(instance);
Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
  • Although `frobnicate` can't take ownership since it takes a reference to `const`. It would need to take the pointer by value. – Mike Seymour Nov 17 '11 at 13:14
  • Though @MikeSeymour's objection is valid, +1 from me for mentioning ownership transfer, which is the key reason for the constructor to be explicit. – Gorpik Nov 17 '11 at 14:03
1

First, solving the immediate issue, you can initialize it like this:

std::auto_ptr<Class A> ptr(new A);

Second, implicit conversions can cause more harm than good, so it's a good reflex to make constructors callable with a single parameter explicit to start with and then ponder if implicitness could be valuable.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • IMHO, the good practice is not to make those constructors explicit, but to think whether you want implicit conversions to happen and then act accordingly. There are lots of valid cases where you actually want those conversions to occur. – Gorpik Nov 17 '11 at 14:01
  • @Gorpik: like all the "Rule Of Thumb" there are exceptions, but I have found that in most cases implicit conversion hurts more than it helps. It's simpler to add a few overloads when you really want it. – Matthieu M. Nov 17 '11 at 14:04
  • I think this rule has more exceptions than most others. But I will admit that, by default, these constructors should be made explicit. If you say "make them explicit unless you want implicit conversions", I agree with you. – Gorpik Nov 17 '11 at 14:20
  • 1
    @Gorpik: true, I modified the answer accordingly. – Matthieu M. Nov 17 '11 at 15:56
0

What's wrong with just using:

std::auto_ptr<T> ptr(new T());

If you allow implicit conversion then you can run into all sorts of issues with implicit casts being inserted where they are least expected.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168