Reputation: 10064
I have a method which creates an object in an auto_ptr
, sticks that auto_ptr
into a vector
, and then returns a raw pointer to the object for convenience.
The problem with this design is that it returns a raw pointer. It's really easy for the caller to misunderstand that this pointer is non-owned and wrap the result of this call into a managed pointer, which causes a memory access violation when that memory gets double free'd.
int main (void)
{
{
std::auto_ptr<int> foo = ThisMethodReturnsNonOwningPtr(); // Uhoh
}
ThisMethodUsesThePtr(); // Crash
return 0;
}
Ideally, I would like to return something like a pointer which can not be converted to a managed pointer so I don't have to worry about the caller doing this.
Alternatively, I might just return an index into the array, but it's real convenient just being able to pass the pointer around, and who knows maybe I will end up shuffling or sorting the array later.
Upvotes: 3
Views: 1318
Reputation: 153909
First, if you can stick an auto_ptr into a vector, it's time to
upgrade your compiler or your library. This hasn't been legal
since the first standard in 1998. If you've got C++11, you can
use std::unique_ptr
; if not, you'll need to keep raw pointers
in the vector. In both cases, you'll want to wrap the vector:
with std::unique_ptr
, so that the client doesn't have to do
anything fancy to get the actual pointer, and with raw pointers,
so that you can manage the memory associated with them.
For the rest, just return a raw pointer. If you have programmers that go around deleting random pointers, you're sunk anyway; most of the time, raw pointers are for navigation, and are just as likely to point to an object with static lifetime as to anything else.
Upvotes: 2
Reputation: 9383
I'm always reluctant to write answers that depend on boost since not everyone is able to use it and it's almost always overkill to pull it in for just one little thing, but if you have it anyway, you could return a boost::optional<&>
. On the surface it doesn't seem an optional reference could work, but it (mostly) does. See boost's documentation.
This would give you the nullability you require (return boost::none
to indicate an error) while making it very clear that the caller is not to take ownership of the object.
Upvotes: 0
Reputation: 1918
If you don't want the object to be deleted in conventional means using delete operator, you could make the destructor of the class private and implement destroy() function which self-destructs the object.
Better would be if you could make the function return something like shared_ptr.
A third option could be just to have a class something like template<typename> struct non_ownership_ptr;
which the function returns instead of a raw pointer. This pointer class just holds the pointer and you would have to explicitly use auto_ptr<T> p=foo().non_owned_ptr;
to avoid (or at least reduce) accidental assignment to auto_ptr or such.
Upvotes: 0
Reputation: 545528
Create a wrapper class template raw_ptr<T>
which encapsulates a T*
.
If you now implement operator*
and operator->
but no conversion operator, you can no longer assign this pointer to another smart pointer, because that assignment would require two custom conversions (raw_ptr<T>
→ T*
→ smart_ptr<T>
), which is not allowed in C++.
Notice that, as others have said, you should not use auto_ptr<T>
– it’s deprecated for good reasons. Use std::unique_ptr<T>
instead. For one thing, you cannot actually safely stick auto_ptr
s into a std::vector
, great care has to be taken to not accidentally copy (and thus invalidate) such pointers.
Upvotes: 1
Reputation: 52659
Stop using auto_ptr and start using unique_ptr or shared_ptr. The latter has reference counting so you can safely return the object and others can use it. The data it points to will not be freed until all references are released.
there is no other alternative if you need to safely return a pointer to the object and still be able to alter the vector. You could use a unique_ptr to prevent a caller from treating the returned pointer as if it owned it.
Last resort is to slap comments on the code to say that the vector owns the object and the pointer is only to be used as a convenience. Its not as good as getting the compiler to check calling code, but it can be the only way if you restrict your options as you mentioned.
Upvotes: 1