C & C++

C & C++

Made by DeepSource

Calling std::move on a trvially copyable parameter CXX-P2010

Performance
Minor

std::move converts an instance from lvalue to rvalue. The move or move-assignment constructor is invoked on such conversions if they exist.

When the following arguments are used with std::move, the std::move has no effect.

  • argument is a const-qualified instance
  • argument is of trivially-copyable type

Move constructor requires non-const rvalue reference argument.

The move constructor reallocate the resources of the receiving object. We can say that, the constructor modifies the argument. Hence, when the const qualifier specifies that an argument's value cannot be changed, move constructor is forced to perform reallocation, making the move redundant. As such const-references can't be moved. The same is applicable to move-assignment constructor.

Calling the move constructor on a trivially-copyable type is often unnecessary.

Exceptions

You should ignore this issue if you know that trivial copy would fit into the platform registers, and would likely be more expensive than a move.

Generally for such types we recommend implementing a custom trivial Copy Constructor to ensure this lint is not raised.

Bad practice

// A function expecting to move 
// a local const qualified object
// to the caller
std::string example_one(void) {
  const std::string name;
  return std::move(name);
}                                                                                                                                                                                 

void receive_str(std::string s);

// A function expecting to move
// a const qualified local object to a callee
void example_two(std::string s) {
  const std::string s{"two"};
  receive_str(std::move(s));
}

// A function expecting to move
// a trivially copyable value
unsigned int get_concurrency_count(void) {
  int count{std::thread::hardware_concurrency()};
  return std::move(count);
}

Recommended

std::string example_one(void) {
  std::string name;
  // `name` is no more const qualified so
  // std::string's move constructor will
  // be invoked.
  return std::move(name);
}                                                                                                                                                                                 

void receive_str(std::string s) {;} 

void example_two(void) {
  std::string s;
  // `s` is no more const qualified so
  // std::string's move constructor will
  // be invoked.
  receive_str(std::move(s));
}

unsigned int get_concurrency_count(void) {
  int cpu_count{std::thread::hardware_concurrency()};
  // copying the values of `int` or other
  // trivially copyable types is preferred.
  // hence call to `std::move` is not needed
  return cpu_count;
}