Look at this program (godbolt):
#include <cstdio>
struct Foo {
~Foo() {
printf("~Foo\n");
}
};
void foo(Foo) {
}
int main() {
foo(Foo());
}
Based on my previous question, this program should not materialize the Foo()
in main
, but just use it as an initializer when calling foo
. So there should be only one instance of Foo
, the parameter of foo()
. However, with MSVC, the code prints
~Foo
~Foo
so there were two instances created, supposedly one for the temporary in main
, and one for foo()
's parameter (note: with gcc, only one ~Foo
line is printed).
Is this standard conformant?
(Note: if I add an empty copy constructor in Foo
, then only one ~Foo
line is printed).
As mentioned by @StoryTeller - Unslander Monica, that MSVC behavior is non‑conformant, i.e it's a compiler bug
The workaround would be to define a trivial copy constructor (e.g. Foo(const Foo&) = default;
). Or, update to the latest MSVC version (C++17)
Since C++17, prvalue temporary materialization is deferred into the direct constructor of the function parameter—so in:
foo(Foo());
there should be only one Foo
object constructed, namely foo
's param, and therefore only one destructor call
GCC/Clang follow that - your program prints a single ~Foo
.
MSVC prints:
~Foo
~Foo
Meaning it creates two instances: one temporary in main
, one for foo
's parameter.
This breaks the C++17 guarantee: the temporary shouldn't materialize independently - so MSVC is failing to implement the standard's prvalue semantics correctly.