I am reviewing some code like this, where A
is a moveable type:
// Returns true exactly when ownership of a is taken
bool MaybeConsume(A&& a) {
if (some condition) {
Consume(std::move(a)); // ???
return true;
}
return false;
}
// ... elsewhere ...
A a;
if (!MaybeConsume(std::move(a))) {
a.DoSomething(); // !!!
}
Our static analysis tool complains that a
is used after being moved (at !!!
). IIUC std::move
is only a static_cast
, and the object a
won't actually get gutted until a move constructor or assignment operator is called (presumably in Consume
). Assuming MaybeConsume
satisfies the contract in the comment,
std::move
at ???
a no-op?(Probably this particular instance can be refactored to avoid the subtlety, but I would still like to ask for my own understanding).
It's a spurious warning from your static analysis tool.
- Does this work?
Yes, MaybeConsume
is doing what the comment says. It's only taking ownership of its argument when some condition
is true (assuming Consume
actually does move construct/assign from its argument).
std::move
is indeed just a fancy static_cast<T&&>
so MaybeConsume(std::move(a))
is not transferring ownership, you're simply binding a reference to MaybeConsume
's parameter.
- Is it UB?
No, you're not making use of a
if MaybeConsume
indicates it has assumed ownership of its argument.
- Is
std::move
at ??? a no-op?
Well, it's a no-op because it's just a static_cast
, but if you meant to ask whether it's unnecessary, then, no, it isn't. Within the body of MaybeConsume
, a
is an lvalue because it has a name. If the signature of Consume
is void Consume(A&&)
, then the code won't compile without that std::move
.
From the example usage you've shown, it seems you're not supposed to call MaybeConsume
with a prvalue argument, since the caller should presumably use the argument in some other manner if the function returns false
. If that's true, then you should change its signature to bool MaybeConsume(A&)
. This will probably make your static analysis tool happy because that would allow you to write if (!MaybeConsume(a))
.