424 lines
18 KiB
Markdown
424 lines
18 KiB
Markdown
[class.temporary]
|
||
|
||
# 6 Basics [[basic]](./#basic)
|
||
|
||
## 6.8 Memory and objects [[basic.memobj]](basic.memobj#class.temporary)
|
||
|
||
### 6.8.7 Temporary objects [class.temporary]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4614)
|
||
|
||
A [*temporary object*](#def:object,temporary "6.8.7 Temporary objects [class.temporary]") is an object created
|
||
|
||
- [(1.1)](#1.1)
|
||
|
||
when a prvalue is converted to an xvalue ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) and
|
||
|
||
- [(1.2)](#1.2)
|
||
|
||
when needed by the implementation to pass or return an object of suitable type (see below)[.](#1.sentence-1)
|
||
|
||
Even when the creation of the temporary object is
|
||
unevaluated ([[expr.context]](expr.context "7.2.3 Context dependence")),
|
||
all the semantic restrictions shall be respected as if the temporary object
|
||
had been created and later destroyed[.](#1.sentence-2)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
This includes accessibility ([[class.access]](class.access "11.8 Member access control")) and whether it is deleted,
|
||
for the constructor selected and for the destructor[.](#1.sentence-3)
|
||
|
||
However, in the special
|
||
case of the operand of a[*decltype-specifier*](dcl.type.decltype#nt:decltype-specifier "9.2.9.6 Decltype specifiers [dcl.type.decltype]") ([[dcl.type.decltype]](dcl.type.decltype "9.2.9.6 Decltype specifiers")), no temporary is introduced,
|
||
so the foregoing does not apply to such a prvalue[.](#1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4638)
|
||
|
||
The materialization of a temporary object is generally
|
||
delayed as long as possible
|
||
in order to avoid creating unnecessary temporary objects[.](#2.sentence-1)
|
||
|
||
[*Note [2](#note-2)*:
|
||
|
||
Temporary objects are materialized:
|
||
|
||
- [(2.1)](#2.1)
|
||
|
||
when binding a reference to a prvalue ([[dcl.init.ref]](dcl.init.ref "9.5.4 References"), [[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"), [[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast"), [[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast"), [[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast"), [[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)")),
|
||
|
||
- [(2.2)](#2.2)
|
||
|
||
when performing certain member accesses on a class prvalue ([[expr.ref]](expr.ref "7.6.1.5 Class member access"), [[expr.mptr.oper]](expr.mptr.oper "7.6.4 Pointer-to-member operators")),
|
||
|
||
- [(2.3)](#2.3)
|
||
|
||
when invoking an implicit object member function on a class prvalue ([[expr.call]](expr.call "7.6.1.3 Function call")),
|
||
|
||
- [(2.4)](#2.4)
|
||
|
||
when performing an array-to-pointer conversion or subscripting on an array prvalue ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion"), [[expr.sub]](expr.sub "7.6.1.2 Subscripting")),
|
||
|
||
- [(2.5)](#2.5)
|
||
|
||
when initializing an object of type std::initializer_list<T> from a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") ([[dcl.init.list]](dcl.init.list "9.5.5 List-initialization")),
|
||
|
||
- [(2.6)](#2.6)
|
||
|
||
for certain unevaluated operands ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification"), [[expr.sizeof]](expr.sizeof "7.6.2.5 Sizeof")), and
|
||
|
||
- [(2.7)](#2.7)
|
||
|
||
when a prvalue that has type other than cv void appears as a discarded-value expression ([[expr.context]](expr.context "7.2.3 Context dependence"))[.](#2.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [1](#example-1)*:
|
||
|
||
Consider the following code:class X {public: X(int);
|
||
X(const X&);
|
||
X& operator=(const X&); ~X();};
|
||
|
||
class Y {public: Y(int);
|
||
Y(Y&&); ~Y();};
|
||
|
||
X f(X);
|
||
Y g(Y);
|
||
|
||
void h() { X a(1);
|
||
X b = f(X(2));
|
||
Y c = g(Y(3));
|
||
a = f(a);}
|
||
|
||
X(2) is constructed in the space used to hold f()'s argument andY(3) is constructed in the space used to hold g()'s argument[.](#2.sentence-4)
|
||
|
||
Likewise,f()'s result is constructed directly in b andg()'s result is constructed directly in c[.](#2.sentence-5)
|
||
|
||
On the other hand, the expressiona = f(a) requires a temporary for
|
||
the result of f(a),
|
||
which is materialized so that the reference parameter
|
||
of X::operator=(const X&) can bind to it[.](#2.sentence-6)
|
||
|
||
â *end example*]
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4706)
|
||
|
||
When an object of class type X is passed to or returned from a potentially-evaluated function call,
|
||
if X is
|
||
|
||
- [(3.1)](#3.1)
|
||
|
||
a scalar type or
|
||
|
||
- [(3.2)](#3.2)
|
||
|
||
a class type that
|
||
has at least one eligible copy or move constructor ([[special]](special "11.4.4 Special member functions")),
|
||
where each such constructor is trivial,
|
||
and the destructor of X is either trivial or deleted,
|
||
|
||
implementations are permitted
|
||
to create temporary objects
|
||
to hold the function parameter or result object,
|
||
as follows:
|
||
|
||
- [(3.3)](#3.3)
|
||
|
||
The first such temporary object
|
||
is constructed from the function argument or return value, respectively[.](#3.3.sentence-1)
|
||
|
||
- [(3.4)](#3.4)
|
||
|
||
Each successive temporary object
|
||
is initialized from the previous one
|
||
as if by direct-initialization if X is a scalar type,
|
||
otherwise by using an eligible trivial constructor[.](#3.4.sentence-1)
|
||
|
||
- [(3.5)](#3.5)
|
||
|
||
The function parameter or return object is initialized
|
||
from the final temporary
|
||
as if by direct-initialization if X is a scalar type,
|
||
otherwise by using an eligible trivial constructor[.](#3.5.sentence-1)
|
||
|
||
(In all cases, the eligible constructor is used
|
||
even if that constructor is inaccessible
|
||
or would not be selected by overload resolution
|
||
to perform a copy or move of the object)[.](#3.sentence-2)
|
||
|
||
[*Note [3](#note-3)*:
|
||
|
||
This latitude is granted to allow objects
|
||
to be passed to or returned from functions in registers[.](#3.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4747)
|
||
|
||
Temporary objects are destroyed as the last step
|
||
in evaluating
|
||
the full-expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))
|
||
that (lexically) contains the point where
|
||
they were created[.](#4.sentence-1)
|
||
|
||
This is true even if that evaluation ends in throwing an exception[.](#4.sentence-2)
|
||
|
||
Thevalue computations andside effects of destroying a temporary object
|
||
are associated only with the full-expression, not with any specific
|
||
subexpression[.](#4.sentence-3)
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4765)
|
||
|
||
There are several contexts in which temporaries are destroyed at a different
|
||
point than the end of the full-expression[.](#5.sentence-1)
|
||
|
||
The first context is when a default constructor is called to initialize
|
||
an element of an array with no corresponding initializer ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#5.sentence-2)
|
||
|
||
The second context is when a copy constructor is called to copy an element of
|
||
an array while the entire array is copied ([[expr.prim.lambda.capture]](expr.prim.lambda.capture "7.5.6.3 Captures"), [[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors"))[.](#5.sentence-3)
|
||
|
||
In either case, if the constructor has one or more default arguments,
|
||
the destruction of every temporary created in a default argument is
|
||
sequenced before the construction of the next array element, if any[.](#5.sentence-4)
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4778)
|
||
|
||
The third context is when a reference binds to a temporary object[.](#6.sentence-1)[25](#footnote-25 "The same rules apply to initialization of an initializer_list object ([dcl.init.list]) with its underlying temporary array.")
|
||
|
||
The temporary object to which the reference is bound or the temporary object
|
||
that is the complete object of a subobject to which the reference is bound
|
||
persists for the lifetime of the reference if the glvalue
|
||
to which the reference is bound
|
||
was obtained through one of the following:
|
||
|
||
- [(6.1)](#6.1)
|
||
|
||
a temporary materialization conversion ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")),
|
||
|
||
- [(6.2)](#6.2)
|
||
|
||
( [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") ),
|
||
where [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is one of these expressions,
|
||
|
||
- [(6.3)](#6.3)
|
||
|
||
subscripting ([[expr.sub]](expr.sub "7.6.1.2 Subscripting")) of an array operand,
|
||
where that operand is one of these expressions,
|
||
|
||
- [(6.4)](#6.4)
|
||
|
||
a class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access")) using the . operator
|
||
where the left operand is one of these expressions and
|
||
the right operand designates a non-static data member of non-reference type,
|
||
|
||
- [(6.5)](#6.5)
|
||
|
||
a pointer-to-member operation ([[expr.mptr.oper]](expr.mptr.oper "7.6.4 Pointer-to-member operators")) using the .* operator
|
||
where the left operand is one of these expressions and
|
||
the right operand is a pointer to data member of non-reference type,
|
||
|
||
- [(6.6)](#6.6)
|
||
|
||
a
|
||
* [(6.6.1)](#6.6.1)
|
||
|
||
const_cast ([[expr.const.cast]](expr.const.cast "7.6.1.11 Const cast")),
|
||
|
||
* [(6.6.2)](#6.6.2)
|
||
|
||
static_cast ([[expr.static.cast]](expr.static.cast "7.6.1.9 Static cast")),
|
||
|
||
* [(6.6.3)](#6.6.3)
|
||
|
||
dynamic_cast ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast")), or
|
||
|
||
* [(6.6.4)](#6.6.4)
|
||
|
||
reinterpret_cast ([[expr.reinterpret.cast]](expr.reinterpret.cast "7.6.1.10 Reinterpret cast"))
|
||
|
||
converting, without a user-defined conversion,
|
||
a glvalue operand that is one of these expressions
|
||
to a glvalue that refers
|
||
to the object designated by the operand, or
|
||
to its complete object or a subobject thereof,
|
||
|
||
- [(6.7)](#6.7)
|
||
|
||
a conditional expression ([[expr.cond]](expr.cond "7.6.16 Conditional operator")) that is a glvalue
|
||
where the second or third operand is one of these expressions, or
|
||
|
||
- [(6.8)](#6.8)
|
||
|
||
a comma expression ([[expr.comma]](expr.comma "7.6.20 Comma operator")) that is a glvalue
|
||
where the right operand is one of these expressions[.](#6.sentence-2)
|
||
|
||
[*Example [2](#example-2)*: template<typename T> using id = T;
|
||
|
||
int i = 1;int&& a = id<int[3]>{1, 2, 3}[i]; // temporary array has same lifetime as aconst int& b = static_cast<const int&>(0); // temporary int has same lifetime as bint&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0); // exactly one of the two temporaries is lifetime-extended â *end example*]
|
||
|
||
[*Note [4](#note-4)*:
|
||
|
||
An explicit type conversion ([[expr.type.conv]](expr.type.conv "7.6.1.4 Explicit type conversion (functional notation)"), [[expr.cast]](expr.cast "7.6.3 Explicit type conversion (cast notation)"))
|
||
is interpreted as
|
||
a sequence of elementary casts,
|
||
covered above[.](#6.sentence-3)
|
||
|
||
[*Example [3](#example-3)*: const int& x = (const int&)1; // temporary for value 1 has same lifetime as x â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[*Note [5](#note-5)*:
|
||
|
||
If a temporary object has a reference member initialized by another temporary object,
|
||
lifetime extension applies recursively to such a member's initializer[.](#6.sentence-4)
|
||
|
||
[*Example [4](#example-4)*: struct S {const int& m;};const S& s = S{1}; // both S and int temporaries have lifetime of s â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
The exceptions to this lifetime rule are:
|
||
|
||
- [(6.9)](#6.9)
|
||
|
||
A temporary object bound to a reference parameter in a function call ([[expr.call]](expr.call "7.6.1.3 Function call"))
|
||
persists until the completion of the full-expression containing the call[.](#6.9.sentence-1)
|
||
|
||
- [(6.10)](#6.10)
|
||
|
||
A temporary object bound to a reference element of
|
||
an aggregate of class type initialized from
|
||
a parenthesized [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||
persists until the completion of the full-expression
|
||
containing the [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]")[.](#6.10.sentence-1)
|
||
|
||
- [(6.11)](#6.11)
|
||
|
||
A temporary bound to a reference in a [*new-initializer*](expr.new#nt:new-initializer "7.6.2.8 New [expr.new]") ([[expr.new]](expr.new "7.6.2.8 New")) persists until the completion of the full-expression containing the [*new-initializer*](expr.new#nt:new-initializer "7.6.2.8 New [expr.new]")[.](#6.11.sentence-1)
|
||
[*Note [6](#note-6)*:
|
||
This might introduce a dangling reference[.](#6.11.sentence-2)
|
||
â *end note*]
|
||
[*Example [5](#example-5)*: struct S { int mi; const std::pair<int,int>& mp; };
|
||
S a { 1, {2,3} };
|
||
S* p = new S{ 1, {2,3} }; // creates dangling reference â *end example*]
|
||
|
||
[7](#7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4886)
|
||
|
||
The fourth context is when a temporary object
|
||
is created in the [*for-range-initializer*](stmt.pre#nt:for-range-initializer "8.1 Preamble [stmt.pre]") of
|
||
either a range-based for statement
|
||
or an enumerating expansion statement ([[stmt.expand]](stmt.expand "8.7 Expansion statements"))[.](#7.sentence-1)
|
||
|
||
If such a temporary object would otherwise be destroyed
|
||
at the end of the [*for-range-initializer*](stmt.pre#nt:for-range-initializer "8.1 Preamble [stmt.pre]") full-expression,
|
||
the object persists for the lifetime of the reference
|
||
initialized by the [*for-range-initializer*](stmt.pre#nt:for-range-initializer "8.1 Preamble [stmt.pre]")[.](#7.sentence-2)
|
||
|
||
[8](#8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4896)
|
||
|
||
The fifth context is when a temporary object is created
|
||
in the [*expansion-initializer*](stmt.expand#nt:expansion-initializer "8.7 Expansion statements [stmt.expand]") of an iterating or destructuring expansion statement[.](#8.sentence-1)
|
||
|
||
If such a temporary object would otherwise be destroyed
|
||
at the end of that [*expansion-initializer*](stmt.expand#nt:expansion-initializer "8.7 Expansion statements [stmt.expand]"),
|
||
the object persists for the lifetime of the reference
|
||
initialized by the [*expansion-initializer*](stmt.expand#nt:expansion-initializer "8.7 Expansion statements [stmt.expand]"), if any[.](#8.sentence-2)
|
||
|
||
[9](#9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4905)
|
||
|
||
The sixth context is when a temporary object
|
||
is created in a structured binding declaration ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations"))[.](#9.sentence-1)
|
||
|
||
Any temporary objects introduced by
|
||
the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")*s* for the variables
|
||
with unique names
|
||
are destroyed at the end of the structured binding declaration[.](#9.sentence-2)
|
||
|
||
[10](#10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4913)
|
||
|
||
Let x and y each be either
|
||
a temporary object whose lifetime is not extended, or
|
||
a function parameter[.](#10.sentence-1)
|
||
|
||
If the lifetimes of x and y end at
|
||
the end of the same full-expression, andx is initialized before y, then
|
||
the destruction of y is sequenced before that of x[.](#10.sentence-2)
|
||
|
||
If the lifetime of two or more temporaries
|
||
with lifetimes extending beyond the full-expressions in which they were created
|
||
ends at the same point,
|
||
these temporaries are destroyed at that point in the reverse order of the
|
||
completion of their construction[.](#10.sentence-3)
|
||
|
||
In addition, the destruction of such temporaries shall
|
||
take into account the ordering of destruction of objects with static, thread, or
|
||
automatic storage duration ([[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration"), [[basic.stc.thread]](basic.stc.thread "6.8.6.3 Thread storage duration"), [[basic.stc.auto]](basic.stc.auto "6.8.6.4 Automatic storage duration"));
|
||
that is, ifobj1 is an object with the same storage duration as the temporary and
|
||
created before the temporary is created
|
||
the temporary shall be destroyed beforeobj1 is destroyed;
|
||
ifobj2 is an object with the same storage duration as the temporary and
|
||
created after the temporary is created
|
||
the temporary shall be destroyed afterobj2 is destroyed[.](#10.sentence-4)
|
||
|
||
[11](#11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L4944)
|
||
|
||
[*Example [6](#example-6)*: struct S { S();
|
||
S(int); friend S operator+(const S&, const S&); ~S();};
|
||
S obj1;const S& cr = S(16)+S(23);
|
||
S obj2;
|
||
|
||
The expressionS(16) + S(23) creates three temporaries:
|
||
a first temporaryT1 to hold the result of the expressionS(16),
|
||
a second temporaryT2 to hold the result of the expressionS(23),
|
||
and a third temporaryT3 to hold the result of the addition of these two expressions[.](#11.sentence-1)
|
||
|
||
The temporaryT3 is then bound to the referencecr[.](#11.sentence-2)
|
||
|
||
It is unspecified whetherT1 orT2 is created first[.](#11.sentence-3)
|
||
|
||
On an implementation whereT1 is created beforeT2,T2 shall be destroyed beforeT1[.](#11.sentence-4)
|
||
|
||
The temporariesT1 andT2 are bound to the reference parameters ofoperator+;
|
||
these temporaries are destroyed at the end of the full-expression
|
||
containing the call tooperator+[.](#11.sentence-5)
|
||
|
||
The temporaryT3 bound to the referencecr is destroyed at the end ofcr's
|
||
lifetime, that is, at the end of the program[.](#11.sentence-6)
|
||
|
||
In addition, the order in whichT3 is destroyed takes into account the destruction order of other objects with
|
||
static storage duration[.](#11.sentence-7)
|
||
|
||
That is, becauseobj1 is constructed beforeT3,
|
||
andT3 is constructed beforeobj2,obj2 shall be destroyed beforeT3,
|
||
andT3 shall be destroyed beforeobj1[.](#11.sentence-8)
|
||
|
||
â *end example*]
|
||
|
||
[25)](#footnote-25)[25)](#footnoteref-25)
|
||
|
||
The same rules apply to initialization of an initializer_list object ([[dcl.init.list]](dcl.init.list "9.5.5 List-initialization")) with its
|
||
underlying temporary array[.](#footnote-25.sentence-1)
|