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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
// Copyright David Abrahams 2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/move/detail/config_begin.hpp>
#include <iostream>
#include <boost/core/lightweight_test.hpp>
#ifdef NO_MOVE
# undef BOOST_COPY_ASSIGN_REF
# define BOOST_COPY_ASSIGN_REF(X) X const&
# undef BOOST_COPYABLE_AND_MOVABLE
# define BOOST_COPYABLE_AND_MOVABLE(X)
# define MOVE(x) (x)
#else
#include <boost/move/utility_core.hpp>
# define MOVE(x) boost::move(x)
#endif
struct X
{
X() : id(instances++)
{
std::cout << "X" << id << ": construct\n";
}
X(X const& rhs) : id(instances++)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";
++copies;
}
// This particular test doesn't exercise assignment, but for
// completeness:
X& operator=(BOOST_COPY_ASSIGN_REF(X) rhs)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n";
return *this;
}
#ifndef NO_MOVE
X& operator=(BOOST_RV_REF(X) rhs)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": move assign\n";
return *this;
}
X(BOOST_RV_REF(X) rhs) : id(instances++)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": ..move construct..\n";
++copies;
}
#endif
~X() { std::cout << "X" << id << ": destroy\n"; }
unsigned id;
static unsigned copies;
static unsigned instances;
BOOST_COPYABLE_AND_MOVABLE(X)
};
unsigned X::copies = 0;
unsigned X::instances = 0;
#define CHECK_COPIES( stmt, min, max, comment ) \
{ \
unsigned const old_copies = X::copies; \
\
std::cout << "\n" comment "\n" #stmt "\n===========\n"; \
{ \
stmt; \
} \
unsigned const n = X::copies - old_copies; \
volatile unsigned const minv(min), maxv(max); \
BOOST_TEST(n <= maxv); \
if (n > maxv) \
std::cout << "*** max is too low or compiler is buggy ***\n"; \
BOOST_TEST(n >= minv); \
if (n < minv) \
std::cout << "*** min is too high or compiler is buggy ***\n"; \
\
std::cout << "-----------\n" \
<< n << "/" << max \
<< " possible copies/moves made\n" \
<< max - n << "/" << max - min \
<< " possible elisions performed\n\n"; \
\
if (n > minv) \
std::cout << "*** " << n - min \
<< " possible elisions missed! ***\n"; \
}
struct trace
{
trace(char const* name)
: m_name(name)
{
std::cout << "->: " << m_name << "\n";
}
~trace()
{
std::cout << "<-: " << m_name << "\n";
}
char const* m_name;
};
void sink(X)
{
trace t("sink");
}
X nrvo_source()
{
trace t("nrvo_source");
X a;
return a;
}
X urvo_source()
{
trace t("urvo_source");
return X();
}
X identity(X a)
{
trace t("identity");
return a;
}
X lvalue_;
X& lvalue()
{
return lvalue_;
}
typedef X rvalue;
X ternary( bool y )
{
X a, b;
return MOVE(y?a:b);
}
int main(int argc, char* argv[])
{
(void)argv;
// Double parens prevent "most vexing parse"
CHECK_COPIES( X a(( lvalue() )), 1U, 1U, "Direct initialization from lvalue");
CHECK_COPIES( X a(( rvalue() )), 0U, 1U, "Direct initialization from rvalue");
CHECK_COPIES( X a = lvalue(), 1U, 1U, "Copy initialization from lvalue" );
CHECK_COPIES( X a = rvalue(), 0U, 1U, "Copy initialization from rvalue" );
CHECK_COPIES( sink( lvalue() ), 1U, 1U, "Pass lvalue by value" );
CHECK_COPIES( sink( rvalue() ), 0U, 1U, "Pass rvalue by value" );
CHECK_COPIES( nrvo_source(), 0U, 1U, "Named return value optimization (NRVO)" );
CHECK_COPIES( urvo_source(), 0U, 1U, "Unnamed return value optimization (URVO)" );
// Just to prove these things compose properly
CHECK_COPIES( X a(urvo_source()), 0U, 2U, "Return value used as ctor arg" );
// Expect to miss one possible elision here
CHECK_COPIES( identity( rvalue() ), 0U, 2U, "Return rvalue passed by value" );
// Expect to miss an elision in at least one of the following lines
CHECK_COPIES( X a = ternary( argc == 1000 ), 0U, 2U, "Return result of ternary operation" );
CHECK_COPIES( X a = ternary( argc != 1000 ), 0U, 2U, "Return result of ternary operation again" );
return boost::report_errors();
}
#include <boost/move/detail/config_end.hpp>
|