The copy constructor can be invoked, but it can also be optimized away (aka "copy elision") in C++14 and older. But in C++17, the elision is guaranteed.
A difference between C++17 and prior standards is that even if the copy ctor call is elided in C++14 and older, it must still exist, even if it's not called. Here's an example:
struct C {
C(int) { }
C(const C&) = delete;
};
int main()
{
C c = C(1);
}
In C++17, this will compile. In C++14 and older, it will not. Even though the compiler might elide the copy ctor in C++14 too, it is not allowed to accept the code. Since C++17 guarantees the elision, the copy ctor is not required to exist.
Note that this is not related to move semantics. C c = C(1)
does not move the temporary into c
. We can delete the move constructor too:
struct C {
C(int) { }
C(C&&) = delete;
C(const C&) = delete;
};
And it still compiles in C++17. This is elision, not a move operation.
There is also no assignment going on here. In declarations, the assignment operators are not called to begin with. But we can be paranoid and delete those too for good measure (both the assignment operator and the move assignment operator):
struct C {
C(int) { }
C(C&&) = delete;
C(const C&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
};
And it will still compile in C++17.