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

2

5

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.

Variegate answered 27/2, 2019 at 9:2 Comment(8)
3) a is copy constructed or even move constructed, because func() returns an rvalue.Choroiditis
Why does that matter to you? Be aware of the as-if rule. Even g++ with -O0 is doing some optimizations.Glaswegian
which version of C++ are you using?Collen
copy elision allowed before C++17, mandatory in some cases since C++17.Awhile
@BasileStarynkevitch "as-if" could apply in this case - but it is not really relevant to copy-elision. Copy-elision is specifically allowed even if the elided constructor or destructor have side-effects.Richelieu
My understanding is that copy elision is a special case of the as-if rule.Glaswegian
@SumitDhingra: Posted an answer taking into account C++11 and C++17 as well.Collen
@Collen C++11 versionVariegate
C
6

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.

Collen answered 27/2, 2019 at 9:21 Comment(2)
With c++17 it goes down to one constructor and one move.Prodigious
Thank you for the explanation. I'll try to read more about it.Variegate
T
2

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.

Trainload answered 27/2, 2019 at 9:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.