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