For instance, if you have a declaration std::unique_ptr<A> a;
, then will the following cause problems?
a->foo(std::move(a));
In my case, foo
is a virtual function, so I can't just move it out of the class. If the above code turns out to cause problems, then what's an alternative way to have the same effect?
Because the unique pointer does not have a copy constructor. Hence you cannot pass it by value, because passing by value requires making a copy.
You cannot copy a unique_ptr . You can only move it. The proper way to do this is with the std::move standard library function. If you take a unique_ptr by value, you can move from it freely.
Use unique_ptr when you want to have single ownership(Exclusive) of the resource. 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.
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.
C++11 and C++14
It depends on the signature of foo
:
foo(std::unique_ptr<A> &&)
, then the call is safe because the pointer retains the old value until foo
begins execution. Whether or not foo
changes the pointer is not relevant because any statement from a called function's execution is sequenced after the evaluation of the expression that names the function.foo(std::unique_ptr<A>)
, then the call has undefined behavior. Though there is a rule that the operands of an operator are evaluated before the computation of the operator's result (so you must have evaluated a
before you can know whose foo
to call, and therefore call it), this is not enough here, because there is no rule saying that function arguments are sequenced after the function name expression. Therefore, a
may have been moved from, and the call to a.operator ->()
contains an attempt to dereference a null pointer.C++17
Since C++17, it is safe. Several new sequencing rules were added, one of which addresses this case precisely:
In a function-call expression, the expression that names the function is sequenced before every argument expression and every default argument.
Source
Ah, well, I should post a safe version for pre-17 C++. It's very simple, just add the necessary sequencing yourself, e.g. by using two statements:
auto aRaw = a.get();
aRaw->foo(std::move(a));
I don't see why it wouldn't be legitimate.
According to this comment:
a = a->imbue(std::move(a), op, std::move(b));
it looks like what you want is a consume operation. That is, the function consumes its inputs (ownership is transferred into the function, and they're deleted upon exiting), which is just what happens.
One of the being-deleted objects happens to be the one you call the member function on, but although that looks like it might be tricky, it sure is OK because at the time of the calling, the object is still guaranteed to live.
You return an object (presumably move since it's an unique_ptr
again) which is reassigned to the original name. So instead of c = a->imbue(a, op, b)
it's a
= a->imbue(a, op, b)
.
That's OK, why would it not be. It's incidentially the same name like the one of an object that just got deleted, but so what. The object is valid, and there's nothing in your way of reassigning something different to a name. You reassign something different to a name when you write x = x + 1;
as well, and nobody would object to that.
Something you may definitively want to avoid is (obviously, but maybe not so obvious?) calling imbue
with the same Expression
object in both locations.
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