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

source code of boost/libs/utility/value_init_test.cpp