fork download
  1. /****************************************************************************
  2. * Snippets, ejemplos, y utilidades del curso de C++ orientado a videojuegos *
  3. * https://github.com/Manu343726/CppVideojuegos/ *
  4. * *
  5. * Copyright © 2014 Manuel Sánchez Pérez *
  6. * *
  7. * This program is free software. It comes without any warranty, to *
  8. * the extent permitted by applicable law. You can redistribute it *
  9. * and/or modify it under the terms of the Do What The Fuck You Want *
  10. * To Public License, Version 2, as published by Sam Hocevar. See *
  11. * http://www.wtfpl.net/ and the COPYING file for more details. *
  12. ****************************************************************************/
  13.  
  14.  
  15. #include <iostream>
  16. #include <utility>
  17. #include <functional>
  18.  
  19.  
  20. template<typename T , bool MESSAGES = true>
  21. class instantation_profiler
  22. {
  23. private:
  24. static std::size_t _alive , _instanced , _destroyed ,
  25. _ctor , _copy_ctor , _move_ctor ,
  26. _copy_assign , _move_assign;
  27.  
  28.  
  29. public:
  30. instantation_profiler()
  31. {
  32. _alive++;
  33. _instanced++;
  34. _ctor++;
  35.  
  36. if( MESSAGES ) std::cout << ">> construction" << std::endl;
  37. }
  38.  
  39. instantation_profiler( const instantation_profiler& )
  40. {
  41. _alive++;
  42. _instanced++;
  43. _copy_ctor++;
  44.  
  45. if( MESSAGES ) std::cout << ">> copy construction" << std::endl;
  46. }
  47.  
  48. instantation_profiler( instantation_profiler&& )
  49. {
  50. _alive++;
  51. _instanced++;
  52. _move_ctor++;
  53.  
  54. if( MESSAGES ) std::cout << ">> move construction" << std::endl;
  55. }
  56.  
  57. instantation_profiler& operator=( const instantation_profiler& )
  58. {
  59. _copy_assign++;
  60.  
  61. if( MESSAGES ) std::cout << ">> copy assigment" << std::endl;
  62. }
  63.  
  64. instantation_profiler& operator=( instantation_profiler&& )
  65. {
  66. _move_assign++;
  67.  
  68. if( MESSAGES ) std::cout << ">> move assigment" << std::endl;
  69. }
  70.  
  71. ~instantation_profiler()
  72. {
  73. _alive--;
  74. _destroyed++;
  75.  
  76. if( MESSAGES ) std::cout << ">> destruction" << std::endl;
  77. }
  78.  
  79.  
  80.  
  81. static std::size_t alive_instances()
  82. {
  83. return _alive;
  84. }
  85.  
  86. static std::size_t instantations()
  87. {
  88. return _instanced;
  89. }
  90.  
  91. static std::size_t destructions()
  92. {
  93. return _destroyed;
  94. }
  95.  
  96. static std::size_t normal_constructions()
  97. {
  98. return _ctor;
  99. }
  100.  
  101. static std::size_t move_constructions()
  102. {
  103. return _move_ctor;
  104. }
  105.  
  106. static std::size_t copy_constructions()
  107. {
  108. return _copy_ctor;
  109. }
  110.  
  111. static std::size_t move_assigments()
  112. {
  113. return _move_assign;
  114. }
  115.  
  116. static std::size_t copy_assigments()
  117. {
  118. return _copy_assign;
  119. }
  120.  
  121.  
  122. static void print_info( std::ostream& out = std::cout )
  123. {
  124. out << "# Normal constructor calls: " << normal_constructions() << std::endl
  125. << "# Copy constructor calls: " << copy_constructions() << std::endl
  126. << "# Move constructor calls: " << move_constructions() << std::endl
  127. << "# Copy assigment calls: " << copy_assigments() << std::endl
  128. << "# Move assigment calls: " << move_assigments() << std::endl
  129. << "# Destructor calls: " << destructions() << std::endl
  130. << "# " << std::endl
  131. << "# Total instantations: " << instantations() << std::endl
  132. << "# Total destructions: " << destructions() << std::endl
  133. << "# Current alive instances: " << alive_instances() << std::endl;
  134. }
  135. };
  136.  
  137. template<typename T , bool MESSAGES>
  138. std::size_t instantation_profiler<T,MESSAGES>::_alive = 0;
  139. template<typename T , bool MESSAGES>
  140. std::size_t instantation_profiler<T,MESSAGES>::_instanced = 0;
  141. template<typename T , bool MESSAGES>
  142. std::size_t instantation_profiler<T,MESSAGES>::_destroyed = 0;
  143. template<typename T , bool MESSAGES>
  144. std::size_t instantation_profiler<T,MESSAGES>::_ctor = 0;
  145. template<typename T , bool MESSAGES>
  146. std::size_t instantation_profiler<T,MESSAGES>::_copy_ctor = 0;
  147. template<typename T , bool MESSAGES>
  148. std::size_t instantation_profiler<T,MESSAGES>::_move_ctor = 0;
  149. template<typename T , bool MESSAGES>
  150. std::size_t instantation_profiler<T,MESSAGES>::_copy_assign = 0;
  151. template<typename T , bool MESSAGES>
  152. std::size_t instantation_profiler<T,MESSAGES>::_move_assign = 0;
  153.  
  154.  
  155. struct foo : public instantation_profiler<foo>
  156. {
  157. int value;
  158. };
  159.  
  160.  
  161.  
  162. //Me suena bastante que Boost tiene una biblioteca con una parida de este estilo...
  163. struct scoped_call
  164. {
  165. private:
  166. std::function<void()> function;
  167.  
  168. public:
  169. scoped_call( const std::function<void()>& f ) : function( f ) {}
  170.  
  171. ~scoped_call()
  172. {
  173. function();
  174. }
  175. };
  176.  
  177.  
  178. foo f()
  179. {
  180. scoped_call chapuza( [](){ std::cout << "Exiting f()..." << std::endl; } );
  181.  
  182. std::cout << "I'm in f(), which returns a foo by value!" << std::endl;
  183.  
  184. return foo();
  185. }
  186.  
  187.  
  188. void g1( foo )
  189. {
  190. scoped_call chapuza( [](){ std::cout << "Exiting g1()..." << std::endl; } );
  191.  
  192. std::cout << "I'm in g1(), which gets a foo by value!" << std::endl;
  193. }
  194.  
  195. void g2( const foo& )
  196. {
  197. scoped_call chapuza( [](){ std::cout << "Exiting g2()..." << std::endl; } );
  198.  
  199. std::cout << "I'm in g2(), which gets a foo by const lvalue reference!" << std::endl;
  200. }
  201.  
  202. void g3( foo&& )
  203. {
  204. scoped_call chapuza( [](){ std::cout << "Exiting g3()..." << std::endl; } );
  205.  
  206. std::cout << "I'm in g3(), which gets an rvalue foo reference!" << std::endl;
  207. }
  208.  
  209. template<typename T>
  210. void h( T&& afoo )
  211. {
  212. scoped_call chapuza( [](){ std::cout << "Exiting h()..." << std::endl; } );
  213.  
  214. std::cout << "I'm in h(), which sends a foo to g() through perfect forwarding!" << std::endl;
  215.  
  216. g1( std::forward<T>( afoo ) );
  217. }
  218.  
  219.  
  220. int main()
  221. {
  222. std::cout << std::endl << "Just before a declaration ( foo a; )" << std::endl; foo a;
  223. std::cout << std::endl << "Just before b declaration ( foo b; )" << std::endl; foo b;
  224. std::cout << std::endl << "Just before c declaration ( foo c; )" << std::endl; foo c;
  225. std::cout << std::endl << "Just before d declaration ( foo d( f() ); )" << std::endl; foo d( f() );
  226.  
  227. std::cout << std::endl << "Just before a to b assigment ( b = a )" << std::endl; b = a;
  228. std::cout << std::endl << "Just before ctor call to b assigment ( b = foo() )" << std::endl; b = foo();
  229. std::cout << std::endl << "Just before f() call to b assigment ( b = f() )" << std::endl; b = f();
  230.  
  231.  
  232.  
  233. std::cout << std::endl << "Just before g1( foo ) call with lvalue arg ( g1( a ) )" << std::endl; g1( a );
  234. std::cout << std::endl << "Just before g1( foo ) call with rvalue arg ( g1( f() ) )" << std::endl; g1( f() );
  235. std::cout << std::endl << "Just before g1( foo ) call with lvalue ==> rvalue arg ( g1( std::move( a ) ) )" << std::endl; g1( std::move( a ) );
  236.  
  237. std::cout << std::endl << "Just before g2( const foo& ) call with lvalue arg ( g2( b ) )" << std::endl; g2( b );
  238. std::cout << std::endl << "Just before g2( const foo& ) call with rvalue arg ( g2( f() ) )" << std::endl; g2( f() );
  239. std::cout << std::endl << "Just before g2( const foo& ) call with lvalue ==> rvalue arg ( g2( std::move( b ) ) )" << std::endl; g2( std::move( b ) );
  240.  
  241. //std::cout << std::endl << "Just before g3( foo&& ) call with lvalue arg ( g3( c ) )" << std::endl; g3( c );
  242. std::cout << std::endl << "Just before g3( foo&& ) call with rvalue arg ( g3( f() ) )" << std::endl; g3( f() );
  243. std::cout << std::endl << "Just before g3( foo&& ) call with lvalue ==> rvalue arg ( g3( std::move( c ) ) )" << std::endl; g3( std::move( c ) );
  244.  
  245.  
  246.  
  247. std::cout << std::endl << "Just before h() call with lvalue arg ( h( d ) )" << std::endl; h( d );
  248. std::cout << std::endl << "Just before h() call with rvalue arg ( h( f() ) )" << std::endl; h( f() );
  249. std::cout << std::endl << "Just before h() call with lvalue ==> rvalue arg ( h( std::move( d ) ) )" << std::endl; h( std::move( d ) );
  250.  
  251. foo::print_info( std::cout );
  252. }
Success #stdin #stdout 0s 3440KB
stdin
Standard input is empty
stdout
Just before a declaration ( foo a; )
>> construction

Just before b declaration ( foo b; )
>> construction

Just before c declaration ( foo c; )
>> construction

Just before d declaration ( foo d( f() ); )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...

Just before a to b assigment ( b = a )
>> copy assigment

Just before ctor call to b assigment ( b = foo() )
>> construction
>> move assigment
>> destruction

Just before f() call to b assigment ( b = f() )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...
>> move assigment
>> destruction

Just before g1( foo ) call with lvalue arg ( g1( a ) )
>> copy construction
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction

Just before g1( foo ) call with rvalue arg ( g1( f() ) )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction

Just before g1( foo ) call with lvalue ==> rvalue arg ( g1( std::move( a ) ) )
>> move construction
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction

Just before g2( const foo& ) call with lvalue arg ( g2( b ) )
I'm in g2(), which gets a foo by const lvalue reference!
Exiting g2()...

Just before g2( const foo& ) call with rvalue arg ( g2( f() ) )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...
I'm in g2(), which gets a foo by const lvalue reference!
Exiting g2()...
>> destruction

Just before g2( const foo& ) call with lvalue ==> rvalue arg ( g2( std::move( b ) ) )
I'm in g2(), which gets a foo by const lvalue reference!
Exiting g2()...

Just before g3( foo&& ) call with rvalue arg ( g3( f() ) )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...
I'm in g3(), which gets an rvalue foo reference!
Exiting g3()...
>> destruction

Just before g3( foo&& ) call with lvalue ==> rvalue arg ( g3( std::move( c ) ) )
I'm in g3(), which gets an rvalue foo reference!
Exiting g3()...

Just before h() call with lvalue arg ( h( d ) )
I'm in h(), which sends a foo to g() through perfect forwarding!
>> copy construction
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction
Exiting h()...

Just before h() call with rvalue arg ( h( f() ) )
I'm in f(), which returns a foo by value!
>> construction
Exiting f()...
I'm in h(), which sends a foo to g() through perfect forwarding!
>> move construction
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction
Exiting h()...
>> destruction

Just before h() call with lvalue ==> rvalue arg ( h( std::move( d ) ) )
I'm in h(), which sends a foo to g() through perfect forwarding!
>> move construction
I'm in g1(), which gets a foo by value!
Exiting g1()...
>> destruction
Exiting h()...
# Normal constructor calls: 10
# Copy constructor calls: 2
# Move constructor calls: 3
# Copy assigment calls: 1
# Move assigment calls: 2
# Destructor calls: 11
# 
# Total instantations: 15
# Total destructions: 11
# Current alive instances: 4
>> destruction
>> destruction
>> destruction
>> destruction