An expression may produce a value not directly identified by a source-level name. C++ may materialize a temporary object for the produced value depending on the expression and the use of the value.
Not every intermediate computation needs its own separate object with distinct storage.
#include <iostream>
int main()
{
std::cout << 10 + 5 << '\n';
return 0;
}
The expression 10 + 5 results in an integer value that is supplied to the output operation. No separate integer object must be materialized by the implementation to hold this intermediate result.
The lifetime of a temporary object has more significance when class objects are materialized, when references are bound to temporaries, and when destructors have side effects.
Unless otherwise mandated by another language rule, a temporary object is destroyed at the conclusion of the full expression that created it. As noted above, it is common for the value produced by such an expression to be read as the initial value of a declared named object (like another temporary, or an lvalue object as it turns out):
int result = 3 * 7;
The result of the expression 3 * 7 is used to initialize result. There is no requirement to materialize a temporary integer object just to initialize result.
The named object continues to exist throughout its own storage duration and lifetime. It does not necessarily depend on any temporary values or objects that it may have used in its initialization.
Directly binding a temporary to a local const lvalue reference, or to a local rvalue reference, normally extends the temporary’s lifetime so that it is destroyed when the reference is destroyed. There are exceptions to this rule (e.g., binding a temporary to a function parameter reference), so it’s not always the case that anything bound to a reference lives as long as that reference.
// Bind by reference without allowing modification through it
const int& kept = 100;
The object will live until the const reference itself exits the scope in which it was declared.
Like a const lvalue reference, an rvalue reference binds the temporary to its scope, but also permits modification. What you observe read from the reference until the declaration scope of the reference expires, is whatever value you last wrote to the reference's target.
// Bind an rvalue reference to a temporary or movable object
int&& mutableTemp = 50;
mutableTemp = 60;
A temporary object may be passed to a function that takes a const lvalue reference, and bind to its reference parameter. In that situation, the temporary lives for the duration of the call to the function...
In that call, the parameter is simply an alias for the temporary.
#include <iostream>
void print(const int& value)
{
std::cout << "Received " << value << '\n';
}
int main()
{
print(25);
return 0;
}
The function's return causes the termination of the scope for which the temporary exists, and it is destroyed.
An lvalue reference cannot normally bind directly to an rvalue expression, though a const lvalue reference can and doing so extends the life of a temporary materialized to the binding of.
A temporary object created as a result of an expression may be bound directly to a const lvalue reference. If this were not so, the object would not be created beyond the declaration statement: By binding a const reference, this lifetime extension causes the temporary to exist as long as the reference exists.
Any future read through the reference accesses that previously created temporary; no new object is instantiated simply because a reference now refers to a temporary.
const int& extended = 40 + 2;
A temporary may also be bound to an rvalue reference. The lifetime of the temporary is extended. As this is an rvalue reference, this temporary may be read and/or written to.
int&& changeable = 7 * 3;
changeable = changeable + 1;
As in the arithmetic expression above, an object can be read, a new value determined, and that value assigned back to the same temporary.
The temporary remains the same object, just the value stored within it can change. That value remains until the reference binding it to scope goes out of scope.
A temporary is simply an object, just one that you haven't given an explicit variable name or used for a longer period than until the expression ends unless you ask an rvalue reference or a const lvalue reference to bind to it.
#include <iostream>
void print(const int& value)
{
std::cout << "Received " << value << '\n';
}
int main()
{
print(25);
const int& extended = 40 + 2;
std::cout << "Extended temporary holds " << extended << '\n';
int&& changeable = 7 * 3;
changeable = changeable + 1;
std::cout << "Modified temporary holds " << changeable << '\n';
return 0;
}
Exercise: Temporary ObjectsStarter code, hints and solutionOpenClose
Practice: Temporary Objects
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Bind a new local int&& to 8 * 4, increment its temporary, and pass it to print. Explain the temporary lifetime and why these int objects have no class member functions.
Mission checklist
- Run the starter as a baseline, then predict the change requested in Your challenge.
- Make that change in your editor; use the lesson-specific hints if you need help.
- Compile and run your answer, then compare with the worked solution and explain the result.
Starter program
This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.
#include <iostream>
void print(const int& value)
{
std::cout << "Received " << value << '\n';
}
int main()
{
print(25);
const int& extended = 40 + 2;
std::cout << "Extended temporary holds " << extended << '\n';
int&& changeable = 7 * 3;
changeable = changeable + 1;
std::cout << "Modified temporary holds " << changeable << '\n';
return 0;
}Hints
The temporary argument to print(25) survives the call. Binding the local reference extended directly to 40 + 2 extends that temporary's lifetime to the reference's lifetime.
extended is a const reference, but changeable is a non-const rvalue reference. Only the latter allows the shown assignment to its temporary value.
Worked solution
another binds directly to a temporary initialized to 32, extending its lifetime to the local reference lifetime. Incrementing it gives 33, which print observes through a const reference. These objects are ints, so there are no class member functions to invoke.
#include <iostream>
void print(const int& value)
{
std::cout << "Received " << value << '\n';
}
int main()
{
print(25);
const int& extended = 40 + 2;
std::cout << "Extended temporary holds " << extended << '\n';
int&& changeable = 7 * 3;
changeable = changeable + 1;
std::cout << "Modified temporary holds " << changeable << '\n';
int&& another = 8 * 4;
++another;
print(another);
return 0;
}
Example output
Received 25
Extended temporary holds 42
Modified temporary holds 22
Received 33
0 comments
No comments yet. Be the first.