performance-no-automatic-move

Finds local variables that cannot be automatically moved due to constness.

Under certain conditions, local values are automatically moved out when returning from a function. A common mistake is to declare local lvalue variables const, which prevents the move.

Example [1]:

StatusOr<std::vector<int>> Cool() {
  std::vector<int> obj = ...;
  return obj;  // calls StatusOr::StatusOr(std::vector<int>&&)
}

StatusOr<std::vector<int>> NotCool() {
  const std::vector<int> obj = ...;
  return obj;  // calls `StatusOr::StatusOr(const std::vector<int>&)`
}

The former version (Cool) should be preferred over the latter (Uncool) as it will avoid allocations and potentially large memory copies.

Semantics

In the example above, StatusOr::StatusOr(T&&) have the same semantics as long as the copy and move constructors for T have the same semantics. Note that there is no guarantee that S::S(T&&) and S::S(const T&) have the same semantics for any single S, so we’re not providing automated fixes for this check, and judgement should be exerted when making the suggested changes.

-Wreturn-std-move

Another case where the move cannot happen is the following:

StatusOr<std::vector<int>> Uncool() {
  std::vector<int>&& obj = ...;
  return obj;  // calls `StatusOr::StatusOr(const std::vector<int>&)`
}

In that case the fix is more consensual: just return std::move(obj). This is handled by the -Wreturn-std-move warning.