user2032932
user2032932

Reputation: 197

passing smart pointer to a function taking reference to a pointer parameter

How can I pass smart ptr to a function taking reference to a pointer as a parameter?

smart_ptr<T> val; // I have this smart pointer

// And I want to pass it to this function, so that this function will fill the smart pointer with proper value
void Foo(T*& sth)
{
    sth = memoryAddress;
}

EDIT Now I get it. Thanks guys for all the answers!

Upvotes: 4

Views: 1786

Answers (3)

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234654

Ugh, this API is ugly.

I will assume that the function promises the pointer it "returns" owns a resource that is to be deleted by the caller in the way that smart_ptr does so, and that the smart_ptr can be initialised from an arbitrary pointer. It cannot be done otherwise.

You can just grab the pointer as you would in the absence of smart pointers and then put it in the smart pointer.

T* ptr;
Foo(ptr);
smart_ptr<T> val(ptr);

It may be the case that the smart pointer already owns something and you want to pass that something to the function, and then replace what the smart pointer owns. That's... even uglier.

I don't know if the function will take ownership of the resource you pass in (normally, I would expect not, but since the API is this ugly, I am not going to swear by it). That leads to two different scenarios.

If the function takes ownership of the resource you pass, i.e., it cares about deleting the pointer itself, the smart pointer type must be one that can relinquish ownership of the resource, like std::unique_ptr with the release() member function. Notably, std::shared_ptr cannot do this (consider that other shared_ptrs may also own it).

So, assuming that the smart pointer has that capability, and the ability to be reinitialised to an arbitrary pointer (like with std::unique_ptr::reset) you can do as follows:

//smart_ptr<T> val;
T* ptr = val.release();
Foo(ptr);
val.reset(ptr);

If the function does not take ownership of the resource, all that is required is the ability to reinitialise with an arbitrary pointer.

//smart_ptr<T> val;
T* ptr = val.get();
Foo(ptr);
val.reset(ptr);

Upvotes: 4

Ben Hymers
Ben Hymers

Reputation: 26576

You can't do that. You can pass the raw pointer using "T* raw = val.get()" then "Foo(raw)" but you can't set a shared_ptr's raw pointer like that inside Foo. If you want Foo to set the shared_ptr, make it take a non-const shared_ptr reference.

Like this:

template<typename T>
Foo(shared_ptr<T>& ptr)
{
    ptr.reset(memoryAddress); // Or assign it, or make_shared, or whatever.
}

shared_ptr<int> intptr;
Foo(intptr);

Or better yet, make Foo return a shared_ptr rather than take it by reference.

Upvotes: 1

James Kanze
James Kanze

Reputation: 154047

The simple answer is that you can't. While the smart pointer almost certainly contains a T* somewhere internally, smart pointers enforce all sorts of invariants, many of which could be broken if you could change this pointer without passing through the user interface. The only solution is to call the function with a raw pointer, and then use the raw pointer to initialize the smart pointer, provided that you're sure that the pointer you get meets the requirements of the smart pointer (e.g. allocated by the new operator).

Upvotes: 7

Related Questions