Scenario:
I am using a method from an old C++ library which returns a raw pointer to SomeClass
where SomeClass
is an exported class from a library header say SomeClass.h
Following is the signature of LibraryMethod
that I am using:
SomeClass* LibraryMethod();
I don't have access to change the library. I am using only the binary & public header which is a typical scenario.
I dont want to use raw pointers in my part of the code. Hence, I have a shared pointer to SomeClass
in my part of the code using the library API.
std::shared_ptr<SomeClass> some_class;
which I initialise like this to avoid storing a raw pointer to SomeClass
some_class = (std::shared_ptr<SomeClass>)LibraryMethod();
This basically works but I want to understand the details here
Question:
Is the above a correct technique ?
Am I causing a leak here ?
Are there any better techniques to handle such a scenario ?
You should follow the same logic above: return smart pointers if the caller wants to manipulate the smart pointer itself, return raw pointers/references if the caller just needs a handle to the underlying object. If you really need to return smart pointers from a function, take it easy and always return by value.
Smart pointers are class objects that behave like raw pointers but manage objects that are new and when or whether to delete them— smart pointers automatically delete the managed object at the appropriate time.
The rule would be this - if you know that an entity must take a certain kind of ownership of the object, always use smart pointers - the one that gives you the kind of ownership you need. If there is no notion of ownership, never use smart pointers.
Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.
You should actually call it as
auto some_class = std::shared_ptr<SomeClass>(LibraryMethod());
This assumes that LibraryMethod
is allocating the pointer and giving ownership of the memory to you.
As currently written, you are trying to cast the raw pointer to a std::shared_ptr
using a C-style cast (which can result in a reinterpret_cast
). Instead you want to construct a std::shared_ptr
using the returned raw pointer.
In your case the correct way should be to use the shared_ptr constructor:
std::shared_ptr<SomeClass> sPtr(LibraryMethod());
BUT first you should be aware what the pointer returned by LibraryMethod()
really means, most libraries returns raw pointer just to say " hei, you can access this object trough this pointer, but watch out, I'm still the one in charge to manage it, so... do not delete it! "
If you are sure that after that call you are in charge to manage it, then ok, you can use a shared_ptr with the peace of mind.
The code works, but it's ugly and fragile. Why mix nice modern C++ (smart pointers) with something as archaic and dangerous as a C-style cast? You're much better off calling reset
:
some_class.reset(LibraryMethod());
The above assumes (as your question seems to indicate) that you already have std::shared_ptr<SomeClass> some_class;
declared somewhere and want to reassign it. If you're creating some_class
just before the call of LibraryMethod
, it's much better to directly initialise it:
std::shared_ptr<SomeClass> some_class(LibraryMethod());
This is then equivalent to CoryKramer's answer.
Note, however, that there's a big assumption hidden in all this code: that LibraryMethod
returns a pointer to memory allocated dynamically via new
and that its caller is responsible for eventually releasing that memory by calling delete
.
Is the above a correct technique ?
Yes, given that the LibraryMethod
allocates the resource with new
, and the library user is responsible for deleting it. Wrapping raw pointers with smart pointers is widely-used for legacy libraries.
Am I causing a leak here ?
No, if you do it correctly. I agree with other answers, but you can also do:
std::shared_ptr<SomeClass> some_class(LibraryMethod());
Are there any better techniques to handle such a scenario ?
One thing to carefully consider is the ownership of the resource allocated by LibraryMethod
. Some argue that shared_ptr
is evil in the sense that it is just a nicer way of introducing a global with dependencies which are hard to track. See this talk or this one @8:40 by Sean Parent for example. You may consider using std::unique_ptr instead if there is an entity in your code that consumes and owns the resource.
Also if LibraryMethod
may throw exceptions you have to handle this case accordingly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With