Copy elision can mean two different things. The "mandatory copy elision" in C++17 is simply a redefinition of what a prvalue is.
auto foo() { return std::mutex{}; }
This is legal and makes sense because within the function std::mutex
isn't "created" yet as far as the language is concerned. Let's not dwell on this case.
In other cases, such as
auto bar()
{
std::vector v{1, 2, 3};
return v;
}
the compiler is allowed to elide the copy/move, after checking that copy/move semantics are legal.
Doesn't it create inconsistencies in the language?
Yes. But there is rarely a language as fixated on consistency as C++, copy elision stands out precisely because C++ prizes consistency. This compromise is made for the overwhelmingly large benefit: we don't want people to worry about performance overhead for writing functions.
The as-if rule is sometimes theoretically enough to generate efficient code, but is often extremely difficult in practice. Compilers have trouble optimizing this for the longest time
delete new int;
trivial as it may be for a human to reason about. We don't want to wait until optimizers are perfect before starting to write functions.