4

I am writing a generic interface for scripting languages and need to call functions that return an object and put the resulting object in a space provided by the scripting language. I have tested with clang++ on Mac OS and the following seems to do the copy/move elision:

class T {
public:
    T() {}
    T(const T &t) {
        std::cout << "Copy" << std::endl;
    }
    T(T&&t) : x(t.x) {
        std::cout << "Move" << std::endl;
    }
private:
    int x = 3;
};

T h()
{
    return T();
}

void buildTInto(void *p)
{
    new (p) T(h());
}

int main(int argc, char *argv[])
{
    alignas(T) char space[sizeof(T)];
    buildTInto(space);
}

Running this code does not print anything. Reading the cpp reference description of copy elision seems to indicate this is the correct behavior, given the example they give which only calls one constructor:

T x = T(T(f())); // only one call to default constructor of T, to initialize x

I think my code is very much similar as without copy elision, the move constructor would be called (just like the T(T(f())) would call two move construction).

Not being a spec lawyer, I am curious if my understanding is correct and I wonder if all C++17 capable compilers do this correctly?

Michel
  • 617
  • 7
  • 14
  • FYI: don't discard the return value of the `new` expression; you should use it instead of casting `space` to a `T*`. – Nicol Bolas Mar 21 '20 at 20:27
  • @NicolBolas You are right but I didn't understand what you meant or how to do it until I read your answer I accepted. I was going to ask you for more info. – Michel Mar 22 '20 at 17:03

1 Answers1

2

Guaranteed elision (aka: C++17's definition of prvalues) applies to the initialization of any object of type T with a prvalue of the same type. That includes objects created by new expressions, including placement new forms.

Indeed, you don't even have to repeat the type at the point of invoking the new expression: new(p) auto(h()); ensures the obligate condition for guaranteed elision.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • This is the first time I see this syntax of auto for a constructor. Have you tested if other compilers do this correctly? I read some older Visual Studio versions did not use to do copy elision correctly. – Michel Mar 22 '20 at 17:03
  • @Michel: The syntax has been legal since `auto` deduction was introduced in C++11. Whether the given object would be moved from or constructed in place was, pre-C++17, a matter for the compiler to decide. And since you used the "C++17" tag in your question, talking about the behavior of pre-C++17-compliant compilers is kind of irrelevant. – Nicol Bolas Mar 22 '20 at 17:06