fork download
  1. #include <iostream>
  2. #include <vector>
  3.  
  4. struct X
  5. {
  6. X() : id(instances++)
  7. {
  8. std::cout << "X" << id << ": construct\n";
  9. }
  10.  
  11. X(std::vector<int>) : id(instances++)
  12. {
  13. std::cout << "X" << id << ": construct (with vector)\n";
  14. }
  15.  
  16. X(X const& rhs) : id(instances++)
  17. {
  18. std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";
  19. ++copies;
  20. }
  21.  
  22. X(X&& rhs) : id(instances++)
  23. {
  24. std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **move**\n";
  25. ++moves;
  26. }
  27.  
  28. // This particular test doesn't exercise assignment, but for
  29. // completeness:
  30. X& operator=(X const& rhs)
  31. {
  32. std::cout << "X" << id << ": <- " << "X" << rhs.id << ": copy-assign\n";
  33. }
  34.  
  35. X& operator=(X&& rhs)
  36. {
  37. std::cout << "X" << id << ": <- " << "X" << rhs.id << ": move-assign\n";
  38. }
  39.  
  40. ~X() { std::cout << "X" << id << ": destroy\n"; }
  41.  
  42. unsigned id;
  43.  
  44. static unsigned copies;
  45. static unsigned moves;
  46. static unsigned instances;
  47. };
  48.  
  49. unsigned X::copies = 0;
  50. unsigned X::moves = 0;
  51. unsigned X::instances = 0;
  52.  
  53. #define CHECK_COPIES( stmt, min, max_copies, max_moves, comment ) \
  54. { \
  55.   unsigned const old_copies = X::copies; \
  56.   unsigned const old_moves = X::moves; \
  57.   \
  58.   std::cout << "\n" comment "\n" #stmt "\n===========\n"; \
  59.   { \
  60.   stmt; \
  61.   } \
  62.   unsigned const n = X::copies - old_copies; \
  63.   unsigned const m = X::moves - old_moves; \
  64.   unsigned const t = n+m; \
  65.   if (t < min) \
  66.   std::cout << "*** min is too high or compiler is buggy ***\n"; \
  67.   if (n > max_copies) \
  68.   std::cout << "*** max_copies is too low or compiler is buggy ***\n";\
  69.   if (m > max_moves) \
  70.   std::cout << "*** max_moves is too low or compiler is buggy ***\n"; \
  71.   \
  72.   \
  73.   std::cout << "-----------\n" \
  74.   << n << "/" << max_copies \
  75.   << " possible copies made\n" \
  76.   << m << "/" << max_moves \
  77.   << " possible moves made\n" \
  78.   << max_copies - t << "/" << max_copies - min \
  79.   << " possible elisions performed\n\n"; \
  80.   \
  81.   if (t > min) \
  82.   std::cout << "*** " << t - min \
  83.   << " possible elisions missed! ***\n"; \
  84. }
  85.  
  86. struct trace
  87. {
  88. trace(char const* name)
  89. : name(name)
  90. {
  91. std::cout << "->: " << name << "\n";
  92. }
  93.  
  94. ~trace()
  95. {
  96. std::cout << "<-: " << name << "\n";
  97. }
  98.  
  99. char const* name;
  100. };
  101.  
  102. std::vector<int> vector()
  103. {
  104. std::vector<int> ret;
  105. return ret;
  106. }
  107.  
  108. void sink(X a)
  109. {
  110. trace t("sink");
  111. }
  112.  
  113. X nrvo_source()
  114. {
  115. trace t("nrvo_source");
  116. X a;
  117. return a;
  118. }
  119.  
  120. X urvo_source()
  121. {
  122. trace t("urvo_source");
  123. return X();
  124. }
  125.  
  126. X nrvo_source_vector()
  127. {
  128. trace t("nrvo_source_vector");
  129. X a( vector() );
  130. return a;
  131. }
  132.  
  133. X urvo_source_vector()
  134. {
  135. trace t("urvo_source_vector");
  136. return X( vector() );
  137. }
  138.  
  139. X identity(X a)
  140. {
  141. trace t("identity");
  142. return a;
  143. }
  144.  
  145. X lvalue_;
  146. X& lvalue()
  147. {
  148. return lvalue_;
  149. }
  150. typedef X rvalue;
  151.  
  152. int main()
  153. {
  154. // Double parens prevent "most vexing parse"
  155. CHECK_COPIES( X a(( lvalue() )), 1, 1, 0, "Direct initialization from lvalue");
  156. CHECK_COPIES( X a(( rvalue() )), 0, 1, 1, "Direct initialization from rvalue");
  157. CHECK_COPIES( X a(( rvalue(vector()) )), 0, 1, 1, "Direct initialization from rvalue, constructed with vector");
  158.  
  159. CHECK_COPIES( X a = lvalue(), 1, 1, 0, "Copy initialization from lvalue" );
  160. CHECK_COPIES( X a = rvalue(), 0, 1, 1, "Copy initialization from rvalue" );
  161. CHECK_COPIES( X a = rvalue(vector()), 0, 1, 1, "Copy initialization from rvalue, constructed with vector" );
  162.  
  163. CHECK_COPIES( sink( lvalue() ), 1, 1, 0, "Pass lvalue by value" );
  164. CHECK_COPIES( sink( rvalue() ), 0, 1, 1, "Pass rvalue by value" );
  165. CHECK_COPIES( sink( rvalue(vector()) ), 0, 1, 1, "Pass rvalue by value, constructed with vector" );
  166.  
  167. CHECK_COPIES( nrvo_source(), 0, 1, 1, "Named return value optimization (NRVO)" );
  168. CHECK_COPIES( nrvo_source_vector(), 0, 1, 1, "Named return value optimization (NRVO), constructed with vector" );
  169.  
  170. CHECK_COPIES( urvo_source(), 0, 1, 1, "Unnamed return value optimization (URVO)" );
  171. CHECK_COPIES( urvo_source_vector(), 0, 1, 1, "Unnamed return value optimization (URVO), constructed with vector" );
  172.  
  173. // Just to prove these things compose properly
  174. CHECK_COPIES( X a(urvo_source()), 0, 2, 2, "Return value used as ctor arg" );
  175.  
  176. // Expect to miss one possible elision here
  177. CHECK_COPIES( identity( rvalue() ), 0, 2, 2, "Return rvalue passed by value" );
  178. }
Success #stdin #stdout 0s 2908KB
stdin
Standard input is empty
stdout
X0: construct

Direct initialization from lvalue
X a(( lvalue() ))
===========
X1: <- X0: **copy**
X1: destroy
-----------
1/1 possible copies made
0/0 possible moves made
0/0 possible elisions performed


Direct initialization from rvalue
X a(( rvalue() ))
===========
X2: construct
X2: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Direct initialization from rvalue, constructed with vector
X a(( rvalue(vector()) ))
===========
X3: construct (with vector)
X3: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Copy initialization from lvalue
X a = lvalue()
===========
X4: <- X0: **copy**
X4: destroy
-----------
1/1 possible copies made
0/0 possible moves made
0/0 possible elisions performed


Copy initialization from rvalue
X a = rvalue()
===========
X5: construct
X5: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Copy initialization from rvalue, constructed with vector
X a = rvalue(vector())
===========
X6: construct (with vector)
X6: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Pass lvalue by value
sink( lvalue() )
===========
X7: <- X0: **copy**
->: sink
<-: sink
X7: destroy
-----------
1/1 possible copies made
0/0 possible moves made
0/0 possible elisions performed


Pass rvalue by value
sink( rvalue() )
===========
X8: construct
->: sink
<-: sink
X8: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Pass rvalue by value, constructed with vector
sink( rvalue(vector()) )
===========
X9: construct (with vector)
->: sink
<-: sink
X9: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Named return value optimization (NRVO)
nrvo_source()
===========
->: nrvo_source
X10: construct
<-: nrvo_source
X10: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Named return value optimization (NRVO), constructed with vector
nrvo_source_vector()
===========
->: nrvo_source_vector
X11: construct (with vector)
<-: nrvo_source_vector
X11: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Unnamed return value optimization (URVO)
urvo_source()
===========
->: urvo_source
X12: construct
<-: urvo_source
X12: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Unnamed return value optimization (URVO), constructed with vector
urvo_source_vector()
===========
->: urvo_source_vector
X13: construct (with vector)
<-: urvo_source_vector
X13: destroy
-----------
0/1 possible copies made
0/1 possible moves made
1/1 possible elisions performed


Return value used as ctor arg
X a(urvo_source())
===========
->: urvo_source
X14: construct
<-: urvo_source
X14: destroy
-----------
0/2 possible copies made
0/2 possible moves made
2/2 possible elisions performed


Return rvalue passed by value
identity( rvalue() )
===========
X15: construct
->: identity
X16: <- X15: **move**
<-: identity
X16: destroy
X15: destroy
-----------
0/2 possible copies made
1/2 possible moves made
1/2 possible elisions performed

*** 1 possible elisions missed! ***
X0: destroy