123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- // 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>
|