Search code examples
c++move-semantics

Can the compiler elide copies of specific data members?


Take this code:

struct Bar { //has non-default copy-constructor
    Bar() = default;
    Bar(const Bar&) {} 
};
struct LargeObject { //has default copy-constructor
    std::array<char, 1000> m_chars;
};
struct Foo {
    Bar m_bar;
    LargeObject m_obj;
};
Foo func() { Foo f; return f; } 

The compiler can't elide a copy when the copy-constructor is specified by the user. What about when a member of a class has a non-default copy constructor? In this code, when f is returned from func, can the compiler elide the copy of m_obj or will everything have to be copied?


Solution

  • Your question is based on a faulty premise. The compiler is perfectly within its rights to elide a copy like this, whether or not the class itself, or one of its members, has a non-default copy (or move) constructor. The benefit of the copy-elision rules introduced since C++11 is to allow this sort of optimization even when it violates the as-if rule.

    If it couldn't do that, copy elision wouldn't be all that useful; a class with even a single smart pointer (which has custom copy and move constructors) would be ineligible for RVO unless the compiler could prove, with certainty, that the as-if rule was not being violated.

    In your specific scenario, the compiler can, and with optimizations enabled, usually will (it's not mandatory since you're relying on non-mandatory NRVO, not the C++17 guaranteed copy elision for simple RVO) implement func by directly constructing the Foo object into the caller-provided storage, without using a separate Foo f that would have to be moved/copied back to the caller.