2

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.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
rozina
  • 4,120
  • 27
  • 49
  • You can do that with `shared_ptr`, but I'm afraid it's not possible with `auto_ptr`. – ichramm Jan 10 '14 at 12:21
  • @ichramm How come? The first one would work if there weren't 2 possible conversions for the compiler to choose from :) – rozina Jan 10 '14 at 12:24
  • 3
    Just so you know, auto_ptr is deprecated, use unique_ptr or shared_ptr instead – user1708860 Jan 10 '14 at 12:27
  • when you call your function and pass derivedPtr to it, your original object derivedPtr will become invalid, use shared_ptr or unique instead as said above – vard Jan 10 '14 at 12:28
  • 3
    @user1708860 I know. There is a comment like yours in every auto_ptr question :) However, some of us only have C++03 and we have to manage with auto_ptr in some cases :) (I work on embedded stuff and we cannot have boost either atm). – rozina Jan 10 '14 at 12:39
  • @rozina I guessed that's the case, but thought to mention it just case it's not... That means you probably really fond of the answer Arne gave (: – user1708860 Jan 10 '14 at 12:46
  • 1
    @user1708860 Hehe yes the answer was "useful" :D – rozina Jan 10 '14 at 12:48

3 Answers3

5

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.

sehe
  • 374,641
  • 47
  • 450
  • 633
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • 4
    Thank you for this info. It does not answer the question at all though. I know auto_ptr is depricated and I know how it works. There is a reason I am using it, but its not really the point of this question. – rozina Jan 10 '14 at 12:44
  • @ArneMertz - not everyone has the luxury of moving to a copuler that supports `unique_ptr`. There's plenty of legacy code out there which isn't being upgraded just because there's a new language standard with some new classes. SteveJessops answer is much more useful here. – Sean Jan 10 '14 at 12:53
  • @rozina it is not only that `unique_ptr` is better: it is that `auto_ptr` is harmful. – Yakk - Adam Nevraumont Jan 10 '14 at 12:56
  • @Yakk Yes it can be if you don't understand how it works. Just like using raw pointers I would say. But in C++03 its the best thing I've got. – rozina Jan 10 '14 at 12:59
  • Thanks for the link to C++03 implementation of `unique_ptr`. I will check it out. I have tried to run boost once, but was stopped by exceptions. We have them disabled in the compiler and I was not able to compile boost. Otherwise I suspect that it would be possible to extract `unique_ptr` from boost. So seeing that this `C++03` implementation uses boost as well it might be a problem. And handwriting some of the template code does not sound easy at all! – rozina Jan 10 '14 at 13:14
  • @rozina you have raw pointers. They are better: less error prone (and that is saying a lot!). So `auto_ptr` is not the best you have. – Yakk - Adam Nevraumont Jan 10 '14 at 13:22
4

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 2
    You can do many workarounds with many caveats, but none will change the fact that `auto_ptr` is ugly and deprecated with reason. – Arne Mertz Jan 10 '14 at 12:32
  • Ok, so we can cast the smart pointer to the correct type, which is rather trivial. But it does not solve the underlying problem of the OP: With raw pointers, I can implicitely convert `Derived*` to `Base*`, with smart pointers I can't. So, at least to me, the question is whether and how we can achieve the same behaviour with smart pointers that we have with raw pointers. – cmaster - reinstate monica Jan 10 '14 at 12:40
  • 2
    @cmaster: only by using a different smart pointer type. If the questioner is not using `auto_ptr` for a good reason, then I'm pretty confident that by now they will be starting to get an inkling they should be looking for those other types. – Steve Jessop Jan 10 '14 at 12:43
  • You've given an answer, yes, and it's a bad answer imo, and therefore I commented it. I had not seen the comment of user1708860. No idea what gives you the impression of me searching for `auto_ptr` mentions on SO, bu it's wrong. – Arne Mertz Jan 10 '14 at 12:43
  • So, do you know of an available smart pointer type that behaves like a raw pointer wrt. implicit type conversions? – cmaster - reinstate monica Jan 10 '14 at 12:50
  • Thank you for the answer! I tested it and it works for the function that takes `auto_ptr` by value. Which is good enough. The solution is not as good as I hoped though, but its the best one so far! :) Thank you for answering the actual question. :) – rozina Jan 10 '14 at 12:54
  • @cmaster: well, `shared_ptr` does and is available *to me* :-) It's not available to the questioner though, and it doesn't have the same semantics as `auto_ptr` in that it doesn't pass exclusive ownership (and can't be released). With `unique_ptr` you'd have to do `function(std::move(derivedPtr));`, again to make the release explicit. Basically, an implicit release is considered harmful by everyone involved in designing these things (even `auto_ptr`, which is still dangerous in other ways). So you'd probably have to write your own to get both, and people would hate you. – Steve Jessop Jan 10 '14 at 12:54
  • Oh, and `shared_ptr` conversions only behave like raw pointer conversions to one level of indirection. You can implicitly convert `T**` to `T const *const`, but not `shared_ptr >` to I can't even be bothered typing it. You would not usually use such a monster anyway. – Steve Jessop Jan 10 '14 at 13:01
  • Ah, thanks for the pointer to `shared_ptr<>`, I didn't know that one has this feature. Nice to know that something like this *is* possible, after all. – cmaster - reinstate monica Jan 10 '14 at 13:16
1

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • If you want a function to take a pointer to memory in heap and then delete that pointer, I would say that `auto_ptr` is still better than raw pointers, since the user of this function sees that ownership is passed. The user must understand `auto_ptr` for this to work ofc. – rozina Jan 10 '14 at 13:17
  • @rozina no: the user sees a variable passed to a function at the point of call. The change of ownership is only clear after you examine the exact signature of the function and the type of the passed variable: and that level of examination will also notuce the comment or argument name that says 'I take ownership of this pointer'. There are few things more error prone than manual memory mansgement: `auto_ptr` is one. If you can learn to use `auto_ptr`, you can learn to use raw pointers easier... – Yakk - Adam Nevraumont Jan 10 '14 at 13:35
  • In that case using a reference for a function parameter has the same problem. The user only sees passing a variable by value. He has to look at the signature to see that the function can change the variable or that there is no copy being made. – rozina Jan 10 '14 at 13:40
  • @rozina yep: but variable changing (rarely) causes that variable to become invalid, or cause UB elsewhere. The state of a pointer (what it owns, if it is nulled, if it points to the same data -- in effect, memory leaks and dangling pointers plus lesser related logic errors) is one of the top kinds of bugs in a C++ application. `auto_ptr` if it reduced these kind of bugs would be aweseome: but instead it multiplies them. – Yakk - Adam Nevraumont Jan 10 '14 at 14:30
  • I agree with that. But a function taking a raw pointer and then deleting it is even worse for me, so I prefer `auto_ptr` for this. And while it is true that it is not seen when reading the code it is seen when writing it, which is when I need the user to know that ownership of heap is lost. I wish though that I was able to use C++11... :) – rozina Jan 10 '14 at 15:08