value_init_test.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // Copyright 2002-2008, Fernando Luis Cacciola Carballal.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Test program for "boost/utility/value_init.hpp"
  8. //
  9. // 21 Ago 2002 (Created) Fernando Cacciola
  10. // 15 Jan 2008 (Added tests regarding compiler issues) Fernando Cacciola, Niels Dekker
  11. // 23 May 2008 (Added tests regarding initialized_value) Niels Dekker
  12. // 21 Ago 2008 (Added swap test) Niels Dekker
  13. #include <cstring> // For memcmp.
  14. #include <iostream>
  15. #include <string>
  16. #include "boost/utility/value_init.hpp"
  17. #ifdef __BORLANDC__
  18. #pragma hdrstop
  19. #endif
  20. #include <boost/core/lightweight_test.hpp>
  21. //
  22. // Sample POD type
  23. //
  24. struct POD
  25. {
  26. POD () : f(0), c(0), i(0){}
  27. POD ( char c_, int i_, float f_ ) : f(f_), c(c_), i(i_) {}
  28. friend std::ostream& operator << ( std::ostream& os, POD const& pod )
  29. { return os << '(' << pod.c << ',' << pod.i << ',' << pod.f << ')' ; }
  30. friend bool operator == ( POD const& lhs, POD const& rhs )
  31. { return lhs.f == rhs.f && lhs.c == rhs.c && lhs.i == rhs.i ; }
  32. float f;
  33. char c;
  34. int i;
  35. } ;
  36. //
  37. // Sample non POD type
  38. //
  39. struct NonPODBase
  40. {
  41. virtual ~NonPODBase() {}
  42. } ;
  43. struct NonPOD : NonPODBase
  44. {
  45. NonPOD () : id() {}
  46. explicit NonPOD ( std::string const& id_) : id(id_) {}
  47. friend std::ostream& operator << ( std::ostream& os, NonPOD const& npod )
  48. { return os << '(' << npod.id << ')' ; }
  49. friend bool operator == ( NonPOD const& lhs, NonPOD const& rhs )
  50. { return lhs.id == rhs.id ; }
  51. std::string id ;
  52. } ;
  53. //
  54. // Sample aggregate POD struct type
  55. // Some compilers do not correctly value-initialize such a struct, for example:
  56. // Borland C++ Report #51854, "Value-initialization: POD struct should be zero-initialized "
  57. // http://qc.codegear.com/wc/qcmain.aspx?d=51854
  58. //
  59. struct AggregatePODStruct
  60. {
  61. float f;
  62. char c;
  63. int i;
  64. };
  65. bool operator == ( AggregatePODStruct const& lhs, AggregatePODStruct const& rhs )
  66. { return lhs.f == rhs.f && lhs.c == rhs.c && lhs.i == rhs.i ; }
  67. //
  68. // An aggregate struct that contains an std::string and an int.
  69. // Pavel Kuznetsov (MetaCommunications Engineering) used a struct like
  70. // this to reproduce the Microsoft Visual C++ compiler bug, reported as
  71. // Feedback ID 100744, "Value-initialization in new-expression"
  72. // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744
  73. //
  74. struct StringAndInt
  75. {
  76. std::string s;
  77. int i;
  78. };
  79. bool operator == ( StringAndInt const& lhs, StringAndInt const& rhs )
  80. { return lhs.s == rhs.s && lhs.i == rhs.i ; }
  81. //
  82. // A struct that has an explicit (user defined) destructor.
  83. // Some compilers do not correctly value-initialize such a struct, for example:
  84. // Microsoft Visual C++, Feedback ID 100744, "Value-initialization in new-expression"
  85. // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744
  86. //
  87. struct StructWithDestructor
  88. {
  89. int i;
  90. ~StructWithDestructor() {}
  91. };
  92. bool operator == ( StructWithDestructor const& lhs, StructWithDestructor const& rhs )
  93. { return lhs.i == rhs.i ; }
  94. //
  95. // A struct that has a virtual function.
  96. // Some compilers do not correctly value-initialize such a struct either, for example:
  97. // Microsoft Visual C++, Feedback ID 100744, "Value-initialization in new-expression"
  98. // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744
  99. //
  100. struct StructWithVirtualFunction
  101. {
  102. int i;
  103. virtual void VirtualFunction();
  104. };
  105. void StructWithVirtualFunction::VirtualFunction()
  106. {
  107. }
  108. bool operator == ( StructWithVirtualFunction const& lhs, StructWithVirtualFunction const& rhs )
  109. { return lhs.i == rhs.i ; }
  110. //
  111. // A struct that is derived from an aggregate POD struct.
  112. // Some compilers do not correctly value-initialize such a struct, for example:
  113. // GCC Bugzilla Bug 30111, "Value-initialization of POD base class doesn't initialize members",
  114. // reported by Jonathan Wakely, http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111
  115. //
  116. struct DerivedFromAggregatePODStruct : AggregatePODStruct
  117. {
  118. DerivedFromAggregatePODStruct() : AggregatePODStruct() {}
  119. };
  120. //
  121. // A struct that wraps an aggregate POD struct as data member.
  122. //
  123. struct AggregatePODStructWrapper
  124. {
  125. AggregatePODStructWrapper() : dataMember() {}
  126. AggregatePODStruct dataMember;
  127. };
  128. bool operator == ( AggregatePODStructWrapper const& lhs, AggregatePODStructWrapper const& rhs )
  129. { return lhs.dataMember == rhs.dataMember ; }
  130. typedef unsigned char ArrayOfBytes[256];
  131. //
  132. // A struct that allows testing whether the appropriate copy functions are called.
  133. //
  134. struct CopyFunctionCallTester
  135. {
  136. bool is_copy_constructed;
  137. bool is_assignment_called;
  138. CopyFunctionCallTester()
  139. : is_copy_constructed(false), is_assignment_called(false) {}
  140. CopyFunctionCallTester(const CopyFunctionCallTester & )
  141. : is_copy_constructed(true), is_assignment_called(false) {}
  142. CopyFunctionCallTester & operator=(const CopyFunctionCallTester & )
  143. {
  144. is_assignment_called = true ;
  145. return *this ;
  146. }
  147. };
  148. //
  149. // A struct that allows testing whether its customized swap function is called.
  150. //
  151. struct SwapFunctionCallTester
  152. {
  153. bool is_custom_swap_called;
  154. int data;
  155. SwapFunctionCallTester()
  156. : is_custom_swap_called(false), data(0) {}
  157. SwapFunctionCallTester(const SwapFunctionCallTester & arg)
  158. : is_custom_swap_called(false), data(arg.data) {}
  159. void swap(SwapFunctionCallTester & arg)
  160. {
  161. std::swap(data, arg.data);
  162. is_custom_swap_called = true;
  163. arg.is_custom_swap_called = true;
  164. }
  165. };
  166. void swap(SwapFunctionCallTester & lhs, SwapFunctionCallTester & rhs)
  167. {
  168. lhs.swap(rhs);
  169. }
  170. template<class T>
  171. void check_initialized_value ( T const& y )
  172. {
  173. T initializedValue = boost::initialized_value ;
  174. BOOST_TEST ( y == initializedValue ) ;
  175. }
  176. #ifdef __BORLANDC__
  177. #if __BORLANDC__ == 0x582
  178. void check_initialized_value( NonPOD const& )
  179. {
  180. // The initialized_value check is skipped for Borland 5.82
  181. // and this type (NonPOD), because the following statement
  182. // won't compile on this particular compiler version:
  183. // NonPOD initializedValue = boost::initialized_value() ;
  184. //
  185. // This is caused by a compiler bug, that is fixed with a newer version
  186. // of the Borland compiler. The Release Notes for Delphi(R) 2007 for
  187. // Win32(R) and C++Builder(R) 2007 (http://dn.codegear.com/article/36575)
  188. // say about similar statements:
  189. // both of these statements now compile but under 5.82 got the error:
  190. // Error E2015: Ambiguity between 'V::V(const A &)' and 'V::V(const V &)'
  191. }
  192. #endif
  193. #endif
  194. //
  195. // This test function tests boost::value_initialized<T> for a specific type T.
  196. // The first argument (y) is assumed have the value of a value-initialized object.
  197. // Returns true on success.
  198. //
  199. template<class T>
  200. bool test ( T const& y, T const& z )
  201. {
  202. const int errors_before_test = boost::detail::test_errors();
  203. check_initialized_value(y);
  204. boost::value_initialized<T> x ;
  205. BOOST_TEST ( y == x ) ;
  206. BOOST_TEST ( y == boost::get(x) ) ;
  207. static_cast<T&>(x) = z ;
  208. boost::get(x) = z ;
  209. BOOST_TEST ( x == z ) ;
  210. boost::value_initialized<T> const x_c ;
  211. BOOST_TEST ( y == x_c ) ;
  212. BOOST_TEST ( y == boost::get(x_c) ) ;
  213. T& x_c_ref = const_cast<T&>( boost::get(x_c) ) ;
  214. x_c_ref = z ;
  215. BOOST_TEST ( x_c == z ) ;
  216. boost::value_initialized<T> const copy1 = x;
  217. BOOST_TEST ( boost::get(copy1) == boost::get(x) ) ;
  218. boost::value_initialized<T> copy2;
  219. copy2 = x;
  220. BOOST_TEST ( boost::get(copy2) == boost::get(x) ) ;
  221. {
  222. boost::value_initialized<T> * ptr = new boost::value_initialized<T>;
  223. BOOST_TEST ( y == *ptr ) ;
  224. delete ptr;
  225. }
  226. #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  227. boost::value_initialized<T const> cx ;
  228. BOOST_TEST ( y == cx ) ;
  229. BOOST_TEST ( y == boost::get(cx) ) ;
  230. boost::value_initialized<T const> const cx_c ;
  231. BOOST_TEST ( y == cx_c ) ;
  232. BOOST_TEST ( y == boost::get(cx_c) ) ;
  233. #endif
  234. return boost::detail::test_errors() == errors_before_test ;
  235. }
  236. int main()
  237. {
  238. BOOST_TEST ( test( 0,1234 ) ) ;
  239. BOOST_TEST ( test( 0.0,12.34 ) ) ;
  240. BOOST_TEST ( test( POD(0,0,0.0), POD('a',1234,56.78f) ) ) ;
  241. BOOST_TEST ( test( NonPOD( std::string() ), NonPOD( std::string("something") ) ) ) ;
  242. NonPOD NonPOD_object( std::string("NonPOD_object") );
  243. BOOST_TEST ( test<NonPOD *>( 0, &NonPOD_object ) ) ;
  244. AggregatePODStruct zeroInitializedAggregatePODStruct = { 0.0f, '\0', 0 };
  245. AggregatePODStruct nonZeroInitializedAggregatePODStruct = { 1.25f, 'a', -1 };
  246. BOOST_TEST ( test(zeroInitializedAggregatePODStruct, nonZeroInitializedAggregatePODStruct) );
  247. StringAndInt stringAndInt0;
  248. StringAndInt stringAndInt1;
  249. stringAndInt0.i = 0;
  250. stringAndInt1.i = 1;
  251. stringAndInt1.s = std::string("1");
  252. BOOST_TEST ( test(stringAndInt0, stringAndInt1) );
  253. StructWithDestructor structWithDestructor0;
  254. StructWithDestructor structWithDestructor1;
  255. structWithDestructor0.i = 0;
  256. structWithDestructor1.i = 1;
  257. BOOST_TEST ( test(structWithDestructor0, structWithDestructor1) );
  258. StructWithVirtualFunction structWithVirtualFunction0;
  259. StructWithVirtualFunction structWithVirtualFunction1;
  260. structWithVirtualFunction0.i = 0;
  261. structWithVirtualFunction1.i = 1;
  262. BOOST_TEST ( test(structWithVirtualFunction0, structWithVirtualFunction1) );
  263. DerivedFromAggregatePODStruct derivedFromAggregatePODStruct0;
  264. DerivedFromAggregatePODStruct derivedFromAggregatePODStruct1;
  265. static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct0) = zeroInitializedAggregatePODStruct;
  266. static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct1) = nonZeroInitializedAggregatePODStruct;
  267. BOOST_TEST ( test(derivedFromAggregatePODStruct0, derivedFromAggregatePODStruct1) );
  268. AggregatePODStructWrapper aggregatePODStructWrapper0;
  269. AggregatePODStructWrapper aggregatePODStructWrapper1;
  270. aggregatePODStructWrapper0.dataMember = zeroInitializedAggregatePODStruct;
  271. aggregatePODStructWrapper1.dataMember = nonZeroInitializedAggregatePODStruct;
  272. BOOST_TEST ( test(aggregatePODStructWrapper0, aggregatePODStructWrapper1) );
  273. ArrayOfBytes zeroInitializedArrayOfBytes = { 0 };
  274. boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes;
  275. BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), zeroInitializedArrayOfBytes, sizeof(ArrayOfBytes)) == 0);
  276. boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes2;
  277. valueInitializedArrayOfBytes2 = valueInitializedArrayOfBytes;
  278. BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), get(valueInitializedArrayOfBytes2), sizeof(ArrayOfBytes)) == 0);
  279. boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester1;
  280. BOOST_TEST ( ! get(copyFunctionCallTester1).is_copy_constructed);
  281. BOOST_TEST ( ! get(copyFunctionCallTester1).is_assignment_called);
  282. boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester2 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1);
  283. BOOST_TEST ( get(copyFunctionCallTester2).is_copy_constructed);
  284. BOOST_TEST ( ! get(copyFunctionCallTester2).is_assignment_called);
  285. boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester3;
  286. copyFunctionCallTester3 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1);
  287. BOOST_TEST ( ! get(copyFunctionCallTester3).is_copy_constructed);
  288. BOOST_TEST ( get(copyFunctionCallTester3).is_assignment_called);
  289. boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester1;
  290. boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester2;
  291. get(swapFunctionCallTester1).data = 1;
  292. get(swapFunctionCallTester2).data = 2;
  293. boost::swap(swapFunctionCallTester1, swapFunctionCallTester2);
  294. BOOST_TEST( get(swapFunctionCallTester1).data == 2 );
  295. BOOST_TEST( get(swapFunctionCallTester2).data == 1 );
  296. BOOST_TEST( get(swapFunctionCallTester1).is_custom_swap_called );
  297. BOOST_TEST( get(swapFunctionCallTester2).is_custom_swap_called );
  298. return boost::report_errors();
  299. }