9

(assuming that I am working with a library or framework that expects usage of raw pointers,)

Is it valid practice to use a smart pointer which owns some data, and then pass the address of the derefenced smart pointer to a function that expects a raw pointer?

Evg
  • 25,259
  • 5
  • 41
  • 83
Max Luchterhand
  • 448
  • 3
  • 10

4 Answers4

9

Yes, that is valid practice. The std smart pointers have a get() member function exactly for that purpose.

In general, when you manage an object through smart pointers, you should only pass the whole smart-pointer-object as is to other functions when these functions imply ownership semantics: if a function will copy a std::shared_ptr, it should accept it by value. Similar for std::unique_ptr. More often than that, a function doesn't have anything to do with ownership, it just wants to act on data and/or behavior passed into it. Then, your first choice should be to take a (const-qualified) reference, because it doesn't have the additional nullptr-state of pointers. Otherwise, a pointer is just fine.

Long story short: if you deal with an API that accepts raw pointers and doesn't do any ownership-related actions on it (delete it, copy the pointee), then it's fine to pass .get() to it.

lubgr
  • 37,368
  • 3
  • 66
  • 117
5

As long as the function doesn't expect to take ownership of the data, definitely.

In fact, that is also how you should design your own functions: use a smart pointer in an interface if, and only if, it should participate in the ownership of the pointee.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • if only everybody would stick to that. Unfortunately a raw pointer as argument isnt a sure indication that the function does not participate in ownership – 463035818_is_not_an_ai Nov 17 '20 at 10:41
  • 1
    @idclev463035818 then the badly behaved function should mention it in its documentation, and be wrapped to ensure proper ownership semantics. – Quentin Nov 17 '20 at 10:45
  • Actually, it's quite a bad behaviour to take a smart pointer if you don't intend to own it. Such behaviour wastes time to increment the reference count when it's not needed. – Michael Chourdakis Nov 22 '20 at 20:05
3

Is it valid practice to use a smart pointer which owns some data, and then pass the address of the derefenced smart pointer to a function that expects a raw pointer?

Yes, that is potentially a valid practice... as long as that function doesn't take ownership of that raw pointer. However, it is important to take note how long the passed pointer will be used. The lifetime of the smart pointer must match or exceed the use of that pointer.

In case the function does take ownership, then it may instead be a valid practice to pass an address released from the smart pointer, but only if the deleter matches what the framework would do with the pointer.

eerorika
  • 232,697
  • 12
  • 197
  • 326
3

The above answers are correct, I 'd only want to add a minor catch: When it's about threaded execution. Then you should be extra-careful about functions that take raw pointers because these may become invalid while executing and the other stack has released them.

When designing your own functions that will go threaded, it might be better to use std::shared_ptr even if the function could use a raw pointer.

struct foo = {...};
void testfoo(foo* msg)
{
}

if (1)    
{
shared<foo> f = std::make_shared<foo>(...);
std::thread t(testfoo,f.get());
t.detach();
}  // whops. f destructed perhaps before testfoo could manipulate it

Better:

void testfoo(std::shared_ptr<foo> msg)
{
}

if (1)    
{
shared<foo> f = std::make_shared<foo>(...);
std::thread t(testfoo,f);
t.detach();
} // f has been copied, so no pointer release
Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • 1
    Actually, it doesn't require that the function itself has to do it. Using the function in a `std::thread` with a lambda as wrapper (capturing the `std::shared_ptr` by value) should be fine as well. – Scheff's Cat Nov 17 '20 at 10:54
  • Win32 callback and `std::shared_ptr`? ;-) – Scheff's Cat Nov 17 '20 at 10:55