Skip to content

Latest commit

 

History

History
55 lines (42 loc) · 2.03 KB

rule.adoc

File metadata and controls

55 lines (42 loc) · 2.03 KB

Why is this an issue?

std::move is not really moving anything, but tells the compiler that a value can be considered as no longer useful. It is technically a cast to a RValue, and allows overload resolution to select the version of a function that will perform destructive operations on that value (therefore actually moving from it).

void f(A const &a); // Just reading from a
void f(A&& a); // I can perform destructive operations on a, like resource stealing

void g() {
    A a;
    f(a); // First overload is selected
    f(std::move(a)); // Second overload is selected
}

As a consequence, calling std::move on an object and then not directly using the returned value as a function argument is not the typical pattern, and may be indicative of a bug. Note that calling a member function on the result of std::move is considered as passing it to a function (as the hidden this parameter), as well as using it as an operand (the called function is the overloaded operator) or initializing an object with it (the called function is the constructor).

Noncompliant code example

void sink(A &&a) {
  std::move(a); // Noncompliant, and not doing anything
}

void f(A &&a) {
  // May or may not move the member name, depending on its type, the intent is not clear anyways,
  // for instance, is `a` supposed to be in a moved-from state after the call?
  g(std::move(a).name); // Noncompliant
}

Compliant solution

void f(A &&a) {
  g(std::move(a.name)); // Compliant, `a.name` is in moved-from state, `a` itself is not

Exceptions

Even if calling a built-in operator or initializing data of built-in type are not function calls, for consistency with cases that involve user-defined types, this rule will not report in those cases:

struct Data {A a; int b; };

Data add(Data &&d1, Data &&d2) {
  return Data{
    std::move(d1.a) + std::move(d2.a), // Compliant, operator+ might have an overload for A&&
    std::move(d1.b) + std::move(d2.b)  // Compliant by exception
  };
}