I am using a class that returns a pointer to memory that I have to
take charge of. I will assign it to a std::auto_ptr so the
deallocation is taken care of. My question is, would the function I am
calling be better if it was declared to return a std::auto_ptr, rather
than a naked pointer? That way it would be self-documenting and I
couldn't accidently forget to assign it to a std::auto_ptr.
An example of where I am being passed a pointer to memory that I have
to take charge of is a virtual ctor that creates an object read from a
message queue. The message is in XML (FWIW). The XML text has to be
read and depending on what is found it creates an object that
corresponds. I will have to free it.
I tend to use std::auto_ptr to declare private data members that are
dynamically allocated, but I have never made a habit of declaring the
return value of functions to be std::auto_ptr where the caller has to
take ownership. I usually manage to avoid having to write functions
that burden the caller in such a way, but a virtual ctor would be a
case where you have to pass the responsibility back, I suppose.
Regards,
Andrew Marlow
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Probably, yes. I am doing the same thing, exactly to raise self-
documentability level :-) of code.
I'd guess that some people might find the idea off-putting, but hey...
By the way, I have a habit, as soon as I have smart pointer on some
type, to typedef it, e.g.:
File SPType.h
class type;
shared_ptr<type> SPType;
weak_ptr<type> WPType;
auto_ptr<type> PType;
Goran.
> ... That way it would be self-documenting and I
> couldn't accidently forget to assign it to a std::auto_ptr.
I vote for auto_ptr: although the casual user will be a bit disoriented,
due to the longer code, this will save him the question whether he
should deallocate that object and how.
> I usually manage to avoid having to write functions
> that burden the caller in such a way,
What burden?
You are actually saving him some work (deallocation) and some thinking
(whether deallocation should take place).
bye
av.
As well as taking care of deletion, using auto_ptr restricts the use of the returned object. You can't put it in a standard container for example. If that restriction is part of the design, all well and good. If not, you may be better off with something more flexible like a shared_ptr.
In general, I do prefer to return a dynamic resource within a container that manages its lifetime.
--
Ian Collins
You can release objects from an auto_ptr if you want to manage its
lifetime by another means, so there's no restriction.
shared_ptr even has a constructor that "steals" ownership from an auto_ptr.
So returning using auto_ptr is a good idea if you want to make the
ownership transfer explicit. Even better if you already use auto_ptr in
other parts of the code.
--
Thomas
Well, yes, but auto_ptr (or equivalent thereof) is eventually
necessary to transfer ownership. With auto_ptr:
auto_ptr<TYPE> P(raw_ptr);
// whatever...
container.insert_or_whatever(P.get());
P.release();
Without:
own(raw_ptr); // metacode, use mechanism of your choosing to "own".
// whatever...
container.insert_or_whatever(raw_ptr);
disown(raw_ptr); // metacode again
See? Same thing both times :-). When used correctly, auto_ptr only
brings good ;-)
Goran.
--
I am aware of this. But thanks for mentioning it because it has made
me think more carefully about what the caller might want to use the
pointer for. If the caller does want the pointer to be in a container
(for whatever reason) then auto_ptr would be a hindrance.
> If that restriction is part of the design, all well and good.
Well, it kind of is.
> If not, you may be better off with something more flexible like a shared_ptr.
No. I think that use of shared_ptr tells the reader that the ownership
is shared. That would be a lie in this case because the virtual ctor
gives the responsibility of ownership exclusively to the caller.
>
> In general, I do prefer to return a dynamic resource within a container that manages its lifetime.
It seems like that would be an auto_ptr in this case :-)
-Andrew M.
--
> By the way, I have a habit, as soon as I have smart pointer on some
> type, to typedef it, e.g.:
>
> File SPType.h
>
> class type;
> shared_ptr<type> SPType;
> weak_ptr<type> WPType;
> auto_ptr<type> PType;
I'm wondering: does that increase readability? Or is it the opposite?
Surely, the first time I see your code I'll need to look up those
typdef. I'm not sure if this will pay off in the long term or not.
bye
av.
With a c++0X-enabled compiler you can use std::unique_ptr instead.
This is a smart pointer that is very similar in behavior to auto_ptr,
has the same overhead as auto_ptr (none), but can be put into
std::containers. More info on unique_ptr here:
http://home.roadrunner.com/~hinnant/unique_ptr03.html
-Howard
> With a c++0X-enabled compiler you can use std::unique_ptr instead.
> This is a smart pointer that is very similar in behavior to auto_ptr,
> has the same overhead as auto_ptr (none), but can be put into
> std::containers. More info on unique_ptr here:
>
> http://home.roadrunner.com/~hinnant/unique_ptr03.html
>
> -Howard
BTW, Howard, I've been meaning to ask you for some time, what's the
difference between c++0x's unique_ptr and your emulation on c++03?
The document talks a lot about unique_ptr in general, but doesn't
mention if there are some differences in usability between the 0x and 03
versions. (I mean, there's no r-value references in 03, so you must've
used a work-around. Did that work-around come for free?).
Also, where should I look for the latest version? Boost vault?
Thanks a lot,
Andy.
The C++03 emulation won't pass all the tests that it is supposed to:
never move from an lvalue, always move from an rvalue, stuff like
that. I don't remember the exact failure mode, and it varies with
implementation technique.
> Also, where should I look for the latest version? Boost vault?
Yes. There has been more serious work on move emulation there. I
keep the unique_ptr03.html link up mostly just because it is a decent
intro to unique_ptr.
-Howard
No, it says to the user that the ownership _can_ be shared. Maybe
the user would like to share the ownership throughout the code,
why would there need to be such a restriction? The documentation
would just say that there is no other reference to the returned
object.
IMHO, unless there is a good reason for a restriction, it is best for
the user to have freedom of choice.
--
Dragan
It cannot be shared between the code that does the 'new' inside the
library and the code that makes the call to the library. The library
documentation says that the pointer being passed back is owned by the
caller and it is the responsibility of the caller to free it.
Or, maybe you mean that the caller receiving the point might want to
share it. Is that what you meant? If so then I think this would be a
very dubious practice. I would rather see the users code take the
responsibility directly. If this is difficult, or there are other
reasons why the users code might want to make the ownership of the
memory shared at that point on, then yes, I suppose you would make it
a shared pointer. I don't think that would be the norm though.
I was looking for general advice on how to declare a function that
employs the virtual ctor pattern where the caller is given the
responsibility to delete the memory. I admit that if such a function
was declared to return an auto_ptr it would make life difficult for
the user code that wanted to share the ownership. But a library that
declares a virtual ctor function in such a way does not want user code
to share the ownership. Is that such a bad thing? Surely it is better
to have a clear division of responsibilities. Surely it is better to
employ coding conventions that make it hard to a user of the library
to get it wrong. Declaring the function to return a naked pointer is
certainly error-prone, whilst at the same time being very flexible.
The user can assign the result to a smart pointer of his own choosing.
Or he can forget to, in which case there will be a memory leak.
-Andrew M.
--
It does? It just requires the caller code to add an extra
.release()
or something close to that to release ownership of the pointer from
the returned auto_ptr.
> But a library that
> declares a virtual ctor function in such a way does not want user code
> to share the ownership.
It doesn't? Why? You seem to be assuming a lot more than I would for a
general purpose virtual ctor pattern.
> Is that such a bad thing? Surely it is better
> to have a clear division of responsibilities. Surely it is better to
> employ coding conventions that make it hard to a user of the library
> to get it wrong.
Yes. It is a good idea to make it hard to do the "bad thing". However,
I remain unconvinced that a simple virtual clone function for a
generic hierarchy knows anything about how the user wants to use the
returned value. Perhaps the user wants single ownership, perhaps he
wants reference counted ownership, or perhaps he wants something else.
Yes, this is what I meant. You also mentioned division
of responsibilities... I'm simply saying the same thing.
The library's responsibility is to create, and
the user's is to use.
Someone mentioned shared_ptr having a constructor from auto_ptr.
Maybe the best way to do things is to return auto_ptr and the user
can choose to move it into a shared_ptr at that point.
Since I myself usually return shared_ptr, I would appreciate if
others comment on this...
--
Dragan
#include <memory>
#include <iostream>
std::auto_ptr<int> source() {return std::auto_ptr<int>(new int(3));}
std::shared_ptr<int> shared_source() {return std::shared_ptr<int>(new
int(3));}
int main()
{
// Ok to share
std::shared_ptr<int> p_shared = source();
std::cout << *p_shared << '\n';
// Ok not to share
std::auto_ptr<int> p_unique = source();
std::cout << *p_unique << '\n';
// Ok to share
std::shared_ptr<int> p_shared2 = shared_source();
std::cout << *p_shared2 << '\n';
// Must share
std::auto_ptr<int> p_unique2 = shared_source();
std::cout << *p_unique2 << '\n';
}
Everything works except the line below "Mush share":
error: conversion from ‘std::shared_ptr<int>’ to non-scalar type
‘std::auto_ptr<int>’ requested
std::auto_ptr<int> p_unique2 = shared_source();
-Howard