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?
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.