Home > Enterprise >  What has changed in C 17 in terms of MOVE elision
What has changed in C 17 in terms of MOVE elision

Time:12-02

Is the "move elision" guaranteed in C 17? Let me explain what I mean by that. In almost every article on what C 17 has introduced, one can find the term: "guaranteed copy elision for RVO" which is kinda self-explanatory. But what about move construction?

Let's look at the code below, it's simple there is a non-copyable type, and two functions, one takes NonCopyable parameter by value, and the second one takes it by rvalue reference.

#include <iostream>

struct NonCopyable
{
  NonCopyable() = default;
  NonCopyable(const NonCopyable&) = delete;

  NonCopyable(NonCopyable&& other) noexcept
  {
    std::cout << "Move ctor\n";
  }
};

void func_by_value(NonCopyable cp)
{
  auto x = std::move(cp);
}

void func_by_rvalue_ref(NonCopyable&& cp)
{
  auto x = std::move(cp);
}

int main() 
{
  std::cout << "Pass by value:\n";
  func_by_value(NonCopyable());

  std::cout << "\nPass by rvalue_ref\n";
  func_by_rvalue_ref(NonCopyable());
}

I compiled it two times using GCC(trunk) using the following flags, and the results are slightly different.

(1) -O0 -std=c 11 -fno-elide-constructors

Program output: 

Pass by value:
Move ctor
Move ctor

Pass by rvalue_ref
Move ctor

(2) -O0 -std=c 17 -fno-elide-constructors

Program output:

Pass by value:
Move ctor

Pass by rvalue_ref
Move ctor

So my question is - what has changed that the move constriction was elided when using C 17? Compiler explorer

CodePudding user response:

Since C 17 mandatory elision of copy/move operations was introduced:

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

  • ...

  • In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

    T x = T(T(f())); // only one call to default constructor of T, to initialize x
    

In the initialization of the parameter cp from the prvalue NonCopyable(), the move construction is required to be elided. Note that mandatory copy elision works for both copy operation and move operation.

  • Related