Function taking a std::auto_ptr<Base> that can accept std::auto_ptr<Derived>

1.1k Views Asked by At

I am trying to create a function that takes an auto_ptr to Base class and I would like to call it with a auto_ptr to Derived class. However I am failing to get it done.

I have tried using it without a reference:

void function(std::auto_ptr<Base> ptr);

std::auto_ptr<Derived> derivedPtr( new ... )
function(derivedPtr); // error:  #348: more than one user-defined conversion from
                      // "std::auto_ptr<Derived>" to "std::auto_ptr<Base>" applies

And with a reference:

void function(std::auto_ptr<Base>& ptr);

std::auto_ptr<Derived> derivedPtr( new ... )
function(derivedPtr); //error:  #304: no instance of overloaded function "function" 
                      // matches the argument list

EDIT: I know auto_ptr is deprecated but I only have access to C++03 and cant access boost. So I would appreciate if the answers would focus on the question itself :) I also do understand the difference of a function taking a reference and a auto_ptr by value. In my actual code the function takes ownership of the auto_ptr so both are fine if I can get the conversion from Derived to Base working.

3

There are 3 best solutions below

9
On BEST ANSWER

You can cast without ambiguity:

function(static_cast<std::auto_ptr<Base> >(derivedPtr));

Be aware that for this to work, Base must have a virtual destructor. Otherwise the code has undefined behavior.

The reason for the ambiguity is as Arne says in his answer -- it's not obvious to the caller whether function takes a value or a reference, and therefore it's not obvious to the caller whether their auto_ptr will be released or not by making the call, and if it is released whether it's converted to a type that can correctly delete the pointer. The ambiguous conversion AFAIK is there to stop you writing such difficult code. By casting, you make it explicit in the calling code that derivedPtr is released.

5
On

It is better to manage memory manually than use auto_ptras its use is so fraught with mistakes.

It is best to use an industrial strength replacememt: at the worst, examine the liberal boost liscense and determine if you can write a clone of your own.

Failimg that, write your own replavement owning_ptr. Create a ownomg_ptr_transfer class template as well. Block copy constructruction on owning_ptr, bit enable implicit conversion from owning_ptr_transfer which takes the underlying poimter. Have a free function or method that moves the underlying pointer to a transfer object.

In essence, if you must, write your own unique_ptr using C++03.

If you will not use someone else's solution, nor will you write your own, then simply mamahe memory manually. auto_ptr is not worth it: it is not just sub optimal compared to unique_ptr, it is actually harmful: its purpose is to make memory management easier, and instead it makes it more error prone. It was an experiment, and it failed.

6
On

You are trying to auto_ptr by value and by reference, which are completely different things. The call by value means, you transfer ownership into the function, since auto_ptr does that on copy. Call by reference means there is only auto_ptr outside the function which keeps the ownership.

Since that difference is so very unintuitive, auto_ptr has been deprecated in the standard of 2011 and authors have been discouraging the use of auto_ptr much longer. In short:

Do not use auto_ptr at all.

Use a unique_ptr if you want to transfer ownership into the function, or a reference or plain pointer if you want to leave it outside the function. It depends on the actual case you have.

Update: since you are mentioning that you have to use C++03 without boost, there is a unique_ptr implementaion for C++03: http://howardhinnant.github.io/unique_ptr03.html It uses a few boost features that can be handwritten easily, so it should be doable to port it to your plaform without having to use boost.