1// Copyright David Abrahams 2009. Distributed under the Boost
2// Software License, Version 1.0. (See accompanying
3// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5#include <iostream>
6#include <boost/core/lightweight_test.hpp>
7
8#ifdef NO_MOVE
9# undef BOOST_COPY_ASSIGN_REF
10# define BOOST_COPY_ASSIGN_REF(X) X const&
11# undef BOOST_COPYABLE_AND_MOVABLE
12# define BOOST_COPYABLE_AND_MOVABLE(X)
13# define MOVE(x) (x)
14#else
15#include <boost/move/utility_core.hpp>
16# define MOVE(x) boost::move(x)
17#endif
18
19struct X
20{
21 X() : id(instances++)
22 {
23 std::cout << "X" << id << ": construct\n";
24 }
25
26 X(X const& rhs) : id(instances++)
27 {
28 std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";
29 ++copies;
30 }
31
32 // This particular test doesn't exercise assignment, but for
33 // completeness:
34 X& operator=(BOOST_COPY_ASSIGN_REF(X) rhs)
35 {
36 std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n";
37 return *this;
38 }
39
40#ifndef NO_MOVE
41 X& operator=(BOOST_RV_REF(X) rhs)
42 {
43 std::cout << "X" << id << ": <- " << "X" << rhs.id << ": move assign\n";
44 return *this;
45 }
46
47 X(BOOST_RV_REF(X) rhs) : id(instances++)
48 {
49 std::cout << "X" << id << ": <- " << "X" << rhs.id << ": ..move construct..\n";
50 ++copies;
51 }
52#endif
53
54 ~X() { std::cout << "X" << id << ": destroy\n"; }
55
56 unsigned id;
57
58 static unsigned copies;
59 static unsigned instances;
60
61 BOOST_COPYABLE_AND_MOVABLE(X)
62};
63
64unsigned X::copies = 0;
65unsigned X::instances = 0;
66
67#define CHECK_COPIES( stmt, min, max, comment ) \
68{ \
69 unsigned const old_copies = X::copies; \
70 \
71 std::cout << "\n" comment "\n" #stmt "\n===========\n"; \
72 { \
73 stmt; \
74 } \
75 unsigned const n = X::copies - old_copies; \
76 volatile unsigned const minv(min), maxv(max); \
77 BOOST_TEST(n <= maxv); \
78 if (n > maxv) \
79 std::cout << "*** max is too low or compiler is buggy ***\n"; \
80 BOOST_TEST(n >= minv); \
81 if (n < minv) \
82 std::cout << "*** min is too high or compiler is buggy ***\n"; \
83 \
84 std::cout << "-----------\n" \
85 << n << "/" << max \
86 << " possible copies/moves made\n" \
87 << max - n << "/" << max - min \
88 << " possible elisions performed\n\n"; \
89 \
90 if (n > minv) \
91 std::cout << "*** " << n - min \
92 << " possible elisions missed! ***\n"; \
93}
94
95struct trace
96{
97 trace(char const* name)
98 : m_name(name)
99 {
100 std::cout << "->: " << m_name << "\n";
101 }
102
103 ~trace()
104 {
105 std::cout << "<-: " << m_name << "\n";
106 }
107
108 char const* m_name;
109};
110
111void sink(X)
112{
113 trace t("sink");
114}
115
116X nrvo_source()
117{
118 trace t("nrvo_source");
119 X a;
120 return a;
121}
122
123X urvo_source()
124{
125 trace t("urvo_source");
126 return X();
127}
128
129X identity(X a)
130{
131 trace t("identity");
132 return a;
133}
134
135X lvalue_;
136X& lvalue()
137{
138 return lvalue_;
139}
140typedef X rvalue;
141
142X ternary( bool y )
143{
144 X a, b;
145 return MOVE(y?a:b);
146}
147
148int main(int argc, char* argv[])
149{
150 ::boost::movelib::ignore(argv);
151 // Double parens prevent "most vexing parse"
152 CHECK_COPIES( X a(( lvalue() )), 1U, 1U, "Direct initialization from lvalue");
153 CHECK_COPIES( X a(( rvalue() )), 0U, 1U, "Direct initialization from rvalue");
154
155 CHECK_COPIES( X a = lvalue(), 1U, 1U, "Copy initialization from lvalue" );
156 CHECK_COPIES( X a = rvalue(), 0U, 1U, "Copy initialization from rvalue" );
157
158 CHECK_COPIES( sink( lvalue() ), 1U, 1U, "Pass lvalue by value" );
159 CHECK_COPIES( sink( rvalue() ), 0U, 1U, "Pass rvalue by value" );
160
161 CHECK_COPIES( nrvo_source(), 0U, 1U, "Named return value optimization (NRVO)" );
162 CHECK_COPIES( urvo_source(), 0U, 1U, "Unnamed return value optimization (URVO)" );
163
164 // Just to prove these things compose properly
165 CHECK_COPIES( X a(urvo_source()), 0U, 2U, "Return value used as ctor arg" );
166
167 // Expect to miss one possible elision here
168 CHECK_COPIES( identity( rvalue() ), 0U, 2U, "Return rvalue passed by value" );
169
170 // Expect to miss an elision in at least one of the following lines
171 CHECK_COPIES( X a = ternary( argc == 1000 ), 0U, 2U, "Return result of ternary operation" );
172 CHECK_COPIES( X a = ternary( argc != 1000 ), 0U, 2U, "Return result of ternary operation again" );
173 return boost::report_errors();
174}
175

source code of boost/libs/move/test/copy_elision_test.cpp