Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assuming no compiler optimization, how many times will this object be created?

Assuming there is no compiler optimization. How many times would OutputBuffer_s type object will be created?

#include <iostream>
#include <vector>

struct OutputBuffer_s {
    int encoded[10];
};

OutputBuffer_s func() {

    OutputBuffer_s s;

    return s;
}

int main() {
    OutputBuffer_s a = func();
}

Initially, I had assumed three times.

1) When func() is called, object s will be created on stack.

2) When func() goes out of scope, it will return copy of object s to main().

3) Copying of value to object a in main(), since value returned by func() would be a temporary.

I know that I'm wrong here, since I compiled with -O0 in g++ but I could see only one creation after overriding the constructors. I want to know where and why I am wrong.

like image 564
Sumit Dhingra Avatar asked Feb 27 '19 09:02

Sumit Dhingra


2 Answers

What you have here copy-elison.

Omits copy and move (since C++11) constructors, resulting in zero-copy pass-by-value semantics.

GCC can elide the constructors even with -O0 option. This is what is happening here. If you want to specifically prevent elision, you can use the -fno-elide-constructors option.

If you use this option, there will be one constructor call and two move constructor calls for C++11.

See demo here.

If you use C++17, there is guaranteed copy-elision in some cases, and here even with the -fno-elide-constructors option, there will be one constructor call and just one move constructor call.

See demo here.

like image 54
P.W Avatar answered Sep 28 '22 04:09

P.W


C++17 has introduced Temporary materialization which I quote:

A prvalue of any complete type T can be converted to an xvalue of the same type T. This conversion initializes a temporary object of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object. If T is a class or array of class type, it must have an accessible and non-deleted destructor.

In that case the extra calls to the contructor will become a move operation. Prior to C++17, which copy elision was not mandatory, the compiler would usually copy elide. As far as I am aware, in your case, a compiler would copy elide anyway (try godbolt and check the produced assembly).

To fully answer, one call to the constructor and one move.

like image 33
KostasRim Avatar answered Sep 28 '22 06:09

KostasRim