Files
2025-10-25 03:02:53 +03:00

146 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[class.copy.elision]
# 11 Classes [[class]](./#class)
## 11.9 Initialization [[class.init]](class.init#class.copy.elision)
### 11.9.6 Copy/move elision [class.copy.elision]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6354)
When certain criteria are met, an implementation is
allowed to omit the creation of a class object from
a source object of the same type (ignoring cv-qualification),
even if the selected constructor and/or the
destructor for the object haveside effects[.](#1.sentence-1)
In such cases, the
implementation treats the source and target of the
omitted initialization as simply two different ways of
referring to the same object[.](#1.sentence-2)
If the first parameter of the
selected constructor is an rvalue reference to the object's type,
the destruction of that object occurs when the target would have been destroyed;
otherwise, the destruction occurs at the later of the times when the
two objects would have been destroyed without the
optimization[.](#1.sentence-3)
[*Note [1](#note-1)*:
Because only one object is destroyed instead of two,
and the creation of one object is omitted,
there is still one object destroyed for each one constructed[.](#1.sentence-4)
— *end note*]
This elision of object creation, called[*copy elision*](#def:copy_elision),
is permitted in the
following circumstances (which may be combined to
eliminate multiple copies):
- [(1.1)](#1.1)
in a return statement ([[stmt.return]](stmt.return "8.8.4The return statement")) in
a function with a class return type,
when the [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") is the name of a non-volatile
object o with automatic storage duration (other than a function parameter or a variable
introduced by the [*exception-declaration*](except.pre#nt:exception-declaration "14.1Preamble[except.pre]") of a[*handler*](except.pre#nt:handler "14.1Preamble[except.pre]") ([[except.handle]](except.handle "14.4Handling an exception"))),
the copy-initialization of the result object can be
omitted by constructing o directly
into the function call's result object;
- [(1.2)](#1.2)
in a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18Throwing an exception[expr.throw]") ([[expr.throw]](expr.throw "7.6.18Throwing an exception")), when the operand
is the name of a non-volatile object o with automatic storage duration
(other than a function parameter or
a variable introduced by
the [*exception-declaration*](except.pre#nt:exception-declaration "14.1Preamble[except.pre]") of a [*handler*](except.pre#nt:handler "14.1Preamble[except.pre]"))
that belongs to a scope that does not contain
the innermost enclosing [*compound-statement*](stmt.block#nt:compound-statement "8.4Compound statement or block[stmt.block]") associated with a [*try-block*](except.pre#nt:try-block "14.1Preamble[except.pre]") (if there is one),
the copy-initialization of the exception object can be omitted by
constructing o directly into the exception object;
- [(1.3)](#1.3)
in a [coroutine](dcl.fct.def.coroutine "9.6.4Coroutine definitions[dcl.fct.def.coroutine]"), a copy of a coroutine parameter
can be omitted and references to that copy replaced with references to the
corresponding parameter if the meaning of the program will be unchanged except for
the execution of a constructor and destructor for the parameter copy object;
- [(1.4)](#1.4)
when the [*exception-declaration*](except.pre#nt:exception-declaration "14.1Preamble[except.pre]") of a[*handler*](except.pre#nt:handler "14.1Preamble[except.pre]") ([[except.handle]](except.handle "14.4Handling an exception")) declares an object o,
the copy-initialization of o can be omitted by treating
the [*exception-declaration*](except.pre#nt:exception-declaration "14.1Preamble[except.pre]") as an alias for the exception
object if the meaning of the program will be unchanged except for the execution
of constructors and destructors for the object declared by the[*exception-declaration*](except.pre#nt:exception-declaration "14.1Preamble[except.pre]")[.](#1.sentence-5)
[*Note [2](#note-2)*:
There cannot be a move from the exception object because it is
always an lvalue[.](#1.4.sentence-2)
— *end note*]
Copy elision is not permitted
where an expression is evaluated in a context
requiring a constant expression ([[expr.const]](expr.const "7.7Constant expressions"))
and in constant initialization ([[basic.start.static]](basic.start.static "6.10.3.2Static initialization"))[.](#1.sentence-6)
[*Note [3](#note-3)*:
It is possible that copy elision is performed
if the same expression
is evaluated in another context[.](#1.sentence-7)
— *end note*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6436)
[*Example [1](#example-1)*: class Thing {public: Thing(); ~Thing();
Thing(const Thing&);};
Thing f() { Thing t; return t;} Thing t2 = f();
struct A {void *p; constexpr A(): p(this) {}};
constexpr A g() { A loc; return loc;}constexpr A a; // well-formed, a.p points to aconstexpr A b = g(); // error: b.p would be dangling ([[expr.const]](expr.const "7.7Constant expressions"))void h() { A c = g(); // well-formed, c.p can point to c or be dangling}
Here the criteria for elision can eliminate
the copying of the object t with automatic storage duration
into the result object for the function call f(),
which is the non-local object t2[.](#2.sentence-1)
Effectively, the construction of t can be viewed as directly initializing t2,
and that object's destruction will occur at program exit[.](#2.sentence-2)
Adding a move constructor to Thing has the same effect, but it is the
move construction from the object with automatic storage duration to t2 that is elided[.](#2.sentence-3)
— *end example*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6481)
[*Example [2](#example-2)*: class Thing {public: Thing(); ~Thing();
Thing(Thing&&);private: Thing(const Thing&);};
Thing f(bool b) { Thing t; if (b)throw t; // OK, Thing(Thing&&) used (or elided) to throw treturn t; // OK, Thing(Thing&&) used (or elided) to return t} Thing t2 = f(false); // OK, no extra copy/move performed, t2 constructed by call to fstruct Weird { Weird();
Weird(Weird&);};
Weird g(bool b) {static Weird w1;
Weird w2; if (b)return w1; // OK, uses Weird(Weird&)elsereturn w2; // error: w2 in this context is an xvalue}int& h(bool b, int i) {static int s; if (b)return s; // OKelsereturn i; // error: i is an xvalue}decltype(auto) h2(Thing t) {return t; // OK, t is an xvalue and h2's return type is Thing}decltype(auto) h3(Thing t) {return (t); // OK, (t) is an xvalue and h3's return type is Thing&&} — *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6534)
[*Example [3](#example-3)*: template<class T> void g(const T&);
template<class T> void f() { T x; try { T y; try { g(x); }catch (...) {if (/*...*/)throw x; // does not movethrow y; // moves} g(y); } catch(...) { g(x);
g(y); // error: y is not in scope}} — *end example*]