Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing a raw pointer returned from a method into a smart pointer

Tags:

c++

c++11

c++14

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 ?

like image 381
TheWaterProgrammer Avatar asked Oct 10 '17 17:10

TheWaterProgrammer


People also ask

Can you return a smart pointer?

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.

Why do we need raw pointers in smart pointers?

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.

In what kind of circumstances would you use a raw pointer instead of a smart pointer?

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.

How many times can a unique pointer be copied to create another smart pointer?

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.


4 Answers

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.

like image 103
Cory Kramer Avatar answered Sep 30 '22 14:09

Cory Kramer


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.

like image 27
elven_inside Avatar answered Sep 30 '22 14:09

elven_inside


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.

like image 22
Angew is no longer proud of SO Avatar answered Sep 30 '22 14:09

Angew is no longer proud of SO


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.

like image 44
AMA Avatar answered Sep 30 '22 16:09

AMA