Question

I want to write a C++ class with a constructor which takes an auto_ptr as its argument so that I could initialize class instances from auto_ptrs to another instance:

#include <memory>

class A
{
public:
  A() {}
  A(std::auto_ptr<A> other) {}
};

std::auto_ptr<A> create()
{
  return std::auto_ptr<A>(new A());
}

void foo()
{
  A x = create();
  // A y ( create() );    // works
}

Compiling this code with g++ -c test.cpp on gcc 4.6 yields the following error messages:

test.cpp: In function ‘void foo()’:
test.cpp:17:16: error: no matching function for call to ‘std::auto_ptr<A>::auto_ptr(std::auto_ptr<A>)’
test.cpp:17:16: note: candidates are:
/usr/include/c++/4.6/backward/auto_ptr.h:260:7: note: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr_ref<_Tp>) [with _Tp = A]
/usr/include/c++/4.6/backward/auto_ptr.h:260:7: note:   no known conversion for argument 1 from ‘std::auto_ptr<A>’ to ‘std::auto_ptr_ref<A>’
/usr/include/c++/4.6/backward/auto_ptr.h:125:9: note: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr<_Tp1>&) [with _Tp1 = A, _Tp = A]
/usr/include/c++/4.6/backward/auto_ptr.h:125:9: note:   no known conversion for argument 1 from ‘std::auto_ptr<A>’ to ‘std::auto_ptr<A>&’
/usr/include/c++/4.6/backward/auto_ptr.h:112:7: note: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr<_Tp>&) [with _Tp = A, std::auto_ptr<_Tp> = std::auto_ptr<A>]
/usr/include/c++/4.6/backward/auto_ptr.h:112:7: note:   no known conversion for argument 1 from ‘std::auto_ptr<A>’ to ‘std::auto_ptr<A>&’
test.cpp:7:3: error:   initializing argument 1 of ‘A::A(std::auto_ptr<A>)’

However, if I use the syntax A y (create()); to create my object, it works.

I want to know why this happens and if there is anything I can do to work around it.

EDIT: I will also point out that if I change the constructor signature to

  A(const std::auto_ptr<A>& other) {}

then everything works beautifully, however this doesn't take ownership of the auto_ptr and thus doesn't have the semantics that I want.

EDIT 2: If I do the same thing with an assignment operator, i.e.,

A& operator=( std::auto_ptr<A> other) {}

then I can do

A x;
x = create();

Why?

Was it helpful?

Solution

You are only allowed one implicit, user-defined conversion. Constructing an auto_ptr from another one already involves the implicit conversion through an auxiliary auto_ptr_ref class, and so you cannot implicitly construct your own class from an auto_ptr.

By using direct initialization, one of the conversions is explicit, and only one implicit user-defined conversion remains, which is fine.

To "work around" the lack of implicit conversion, you can either modify your constructor to take the auto_ptr by (non-const) reference, or migrate everything to unique_ptrs.

OTHER TIPS

Use:

A(std::auto_ptr<A>& other)
              //  ^ Note the reference!
{
    // Assign interned auto_ptr member here, which you definitely should have
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top