c++c++17copy-elision

Is visual studio standard conformant when it seemingly doesn't elide a copy when calling a function


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


Solution

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