-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathRVO_NRVO_copy_elision.cpp
More file actions
executable file
·127 lines (106 loc) · 4.18 KB
/
Copy pathRVO_NRVO_copy_elision.cpp
File metadata and controls
executable file
·127 lines (106 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Demo for docs/copy_elision.md
//
// Each Widget operation prints, so the output literally shows how many
// copy/move ctors actually ran. Fewer prints than you'd "expect" means
// the compiler elided.
//
// Build (from build/): cmake --build . --target RVO_NRVO_copy_elision -j 4
// Run: ./Debug/RVO_NRVO_copy_elision
//
// To see what elision is hiding, recompile with:
// g++ -std=c++17 -fno-elide-constructors ...
// Mandatory C++17 cases (RVO from prvalues) still elide; NRVO does not.
#include <iostream>
#include <utility>
struct Widget {
Widget() { std::cout << " default\n"; }
Widget(const Widget&) { std::cout << " copy\n"; }
Widget(Widget&&) noexcept { std::cout << " move\n"; }
~Widget() { std::cout << " ~Widget\n"; }
};
// --- §3 RVO: return a prvalue ---------------------------------------------
Widget rvo_prvalue() {
return Widget{}; // prvalue — C++17 mandatory elision
}
// --- §3 RVO: conditional prvalues -----------------------------------------
Widget rvo_conditional(bool flag) {
return flag ? Widget{} : Widget{}; // both arms are prvalues
}
// --- §4 NRVO: named local --------------------------------------------------
Widget nrvo_named() {
Widget local;
return local; // permitted (not mandatory)
}
// --- §4.1 NRVO failure: multiple named locals on different paths ----------
Widget nrvo_fails_branch(bool flag) {
Widget a, b;
return flag ? a : b; // compiler can't pre-pick a slot
}
// --- §4.1 NRVO failure: returning a function parameter --------------------
Widget nrvo_fails_param(Widget src) {
return src; // src lives in the parameter slot
}
// --- §4.2 The `return std::move(local)` anti-pattern ----------------------
Widget pessimizing_move() {
Widget local;
return std::move(local); // disables NRVO, forces a move
}
// --- §5.1 C++17 mandatory elision: immovable type returned by prvalue -----
struct Immovable {
int value;
Immovable() : value(42) { std::cout << " Immovable default\n"; }
Immovable(const Immovable&) = delete;
Immovable(Immovable&&) = delete;
Immovable& operator=(const Immovable&) = delete;
Immovable& operator=(Immovable&&) = delete;
~Immovable() { std::cout << " ~Immovable\n"; }
};
Immovable make_immovable() {
return Immovable{}; // legal in C++17 — no ctor call needed
}
// --- §6 Copy elision in exception handling --------------------------------
void throw_and_catch() {
try {
throw Widget{}; // prvalue exception object
} catch (const Widget&) { // catch-by-reference: no copy
std::cout << " (caught by reference)\n";
}
}
// --------------------------------------------------------------------------
static void header(const char* title) {
std::cout << "\n=== " << title << " ===\n";
}
int main() {
header("1. RVO from prvalue return (expect: default + ~Widget)");
{
Widget w = rvo_prvalue();
}
header("2. RVO with conditional prvalues (expect: default + ~Widget)");
{
Widget w = rvo_conditional(true);
}
header("3. NRVO with named local (expect: default + ~Widget)");
{
Widget w = nrvo_named();
}
header("4. NRVO fails: branched named locals (expect: 2 defaults + copy/move + 3 dtors)");
{
Widget w = nrvo_fails_branch(true);
}
header("5. NRVO fails: returning a parameter (expect: default + move + dtors)");
{
Widget w = nrvo_fails_param(Widget{});
}
header("6. Anti-pattern: return std::move(local) (expect: default + move + dtors)");
{
Widget w = pessimizing_move();
}
header("7. C++17 mandatory elision of immovable prvalue (expect: 1 default + 1 dtor)");
{
Immovable x = make_immovable();
std::cout << " value = " << x.value << "\n";
}
header("8. Exception: throw prvalue, catch by ref (expect: default + ~Widget)");
throw_and_catch();
std::cout << "\n=== done ===\n";
}