I have an easy question about shared pointers and move semantics. Imagine that I have a class with a private member variable like this:
class C
{
private:
std::shared_ptr<std::vector<uint8_t>> buffer;
}
I need to provide public getters and setters. The getter seems obvious:
std::shared_ptr<std::vector<uint8_t>> C::GetBuffer()
{
return buffer;
}
However, being new to C++ I'm having trouble writing the setter. I could do something like this:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>> input)
{
buffer = input;
}
However that results in a copy of input to buffer, but I don't really want the caller to have shared ownership. Instead I want to move the data. I tried to solve this with:
void C::SetBuffer(std::shared_ptr<std::vector<uint8_t>>& input)
{
buffer(std::move(input));
}
But this is an error: "call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type."
Can somebody help me understand:
1. What is going on here?
2. How to best implement the setter?
You can fix the error you're getting by writing this:
void C::SetBuffer( std::shared_ptr<std::vector<uint8_t> > &input ) {
buffer = move(input);
}
This will call shared_ptr
's move-assignment operator, which will pilfer input
. However, this won't really stop the caller from having shared ownership. Once you accept (or dispense) a shared_ptr
from/to an unknown client, you don't have much in the way of control about who shares ownership. Even if input
is pilfered, there's no reason to expect that input
was the only copy of the shared_ptr
you just received. If, for example, the function that called SetBuffer()
took whatever became input
from its caller by value, that higher-level copy of the pointer will continue to share ownership.
Note that your getter has a similar issue. You're returning a shared_ptr
to your own internal object (and what's more, it's a shared_ptr
-to-non-const
, so the client can modify the shared state) and wherever that shared_ptr
gets passed around after you provide it, those copies will also share (mutable) ownership.
If you really want to ensure you have exclusive ownership, you can hold a unique_ptr
instead of a shared_ptr
and have your getter pass back a const
-reference, and your setter take either a unique_ptr
or a value.