MathFromScratch
MathFromScratch

Reputation: 133

Is there a c++ temporary rvalue for constants

Are temporaries generated in C++ when a literal constant / basic types is assigned to a variable? Does this differ between C++ specifications (c++98,c++11,c++14,c++17,etc)?

int a = 1; // 1 here is likely loaded in microcode level, right? But not guaranteed not to generate a temp value

int b = 1+2; // evaluated to 3 at compile time as const, also 3 might not exist in microcode. Likely temp value

auto c = 3; // creates an int based on 3. No temp value

int a{1}; //no temp value?

I am reading https://herbsutter.com/2013/05/13/gotw-2-solution-temporary-objects/.

Also, I assume I am completely wrong on all of this

Upvotes: 3

Views: 129

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

C++ the language is defined by the standard. In the standard it describes the behavior of an abstract machine operating on well formed programs doing behavior defined by the standard.

A core rule of C++ is the as-if rule. Under the as-if rule, the compiler's generated code is free to behave however it wants, so long as its behavior observable under the standard matches what the standard states.

There is no way to observe, under the standard, the existence of the 1 in 1+2. So, under the standard, the compiler is free to compile code where the 1 never existed, and simply generate the number 3.

What more, if you never use the variable x, the statement

int x = 1+2+3+4;

has no effect. So the compilers is free to never use it. In fact, you never take a reference to the value x or change its value, then the variable x can be completely eliminated from the program. Whenever it is used, the value 10 can replace it.

Typically, optimizing compilers do something called "static simple assignment", where even if you assign to x multiple times it actually treats it as a sequence of assignments to different variables. Only when you take a reference or pointer to x does this break down.

So

int x = 1+2+3+4;
std::cout << x;
x += 20;
std::cout << x;

can be treated as

const int x_0 = 10;
std::cout << x_0;
const int x_1 = x_0 + 20;
std::cout << x_1;

and then the obvious optimizations of simply printing 10 and 30 fall right out.

When reasoning about C++ this way, you have to pay attention to what observable behavior is, and know the compiler is free to throw out the rest. With a bit of care this lets you make zero-cost abstractions where intermediate results never actually exist at runtime.

Upvotes: 3

If we're going to be specific we have to distinguish temporary objects and temporary values. A temporary object appertains to class types. This is what the C++ standard discusses and what people usually mean when they talk about "temporaries". When people talk about temporary values, what they really mean are intermediate results. i.e, swapping values out of registers.

All of your examples:

int a = 1;
int b = 1+2;
auto c = 3;
int d{1};

do not create any "temporaries", because none have to be created. "1+2" is likely to be folded into a constant. No opcodes even have to be generated. The minimal assembly for this program is:

a:
        .long   1
b:
        .long   3
c:
        .long   3
d:
        .long   1

The GOTW you linked is more concerned with the overarching debate about "passing by value" and minimizing unnecessary copies of class temporary objects. There's very little reason to care about literal types, whether temporaries are created or not, unless you're prematurely optimizing.

Upvotes: 2

Related Questions