Consider the following program:
#include <iostream>
#include <utility>
class T {
public:
T() { printf("address at construction: %zx\n", (uintptr_t)this); }
// T(const T&) { printf("copy-constructed\n"); } // helps
// T(T&&) { printf("move-constructed\n"); } // helps
// T(const T&) = default; // does not help
// T(T&&) = default; // does not help
};
T f() { return T(); }
int main() {
T x = f();
printf("address after construction: %zx\n", (uintptr_t)&x);
return 0;
}
Compiling with g++ -std=c++17 test.cpp
gives the following output (same with clang++
):
address at construction: 7ffcc7626857
address after construction: 7ffcc7626887
Based on the C++ reference I would expect the program to output two equal addresses because the copy/move should be guaranteed to be elided (at least in C++17).
If I explicitly define either the copy or the move constructor or both (see commented out lines in the example), the program gives the expected output (even with C++11):
address at construction: 7ffff4be4547
address after construction: 7ffff4be4547
Simply setting the copy/move constructors to default
does not help.
The reference explicitly states
[The copy/move constructors] need not be present or accessible
So what am I missing here?