1 // Copyright 2002-2008, Fernando Luis Cacciola Carballal.
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)
7 // Test program for "boost/utility/value_init.hpp"
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
14 #include <cstring> // For memcmp.
18 #include "boost/utility/value_init.hpp"
19 #include <boost/shared_ptr.hpp>
25 #include "boost/test/minimal.hpp"
32 POD () : c(0), i(0), f(0) {}
34 POD ( char c_
, int i_
, float f_
) : c(c_
), i(i_
), f(f_
) {}
36 friend std::ostream
& operator << ( std::ostream
& os
, POD
const& pod
)
37 { return os
<< '(' << pod
.c
<< ',' << pod
.i
<< ',' << pod
.f
<< ')' ; }
39 friend bool operator == ( POD
const& lhs
, POD
const& rhs
)
40 { return lhs
.f
== rhs
.f
&& lhs
.c
== rhs
.c
&& lhs
.i
== rhs
.i
; }
48 // Sample non POD type
52 virtual ~NonPODBase() {}
54 struct NonPOD
: NonPODBase
57 explicit NonPOD ( std::string
const& id_
) : id(id_
) {}
59 friend std::ostream
& operator << ( std::ostream
& os
, NonPOD
const& npod
)
60 { return os
<< '(' << npod
.id
<< ')' ; }
62 friend bool operator == ( NonPOD
const& lhs
, NonPOD
const& rhs
)
63 { return lhs
.id
== rhs
.id
; }
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
74 struct AggregatePODStruct
81 bool operator == ( AggregatePODStruct
const& lhs
, AggregatePODStruct
const& rhs
)
82 { return lhs
.f
== rhs
.f
&& lhs
.c
== rhs
.c
&& lhs
.i
== rhs
.i
; }
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
97 bool operator == ( StringAndInt
const& lhs
, StringAndInt
const& rhs
)
98 { return lhs
.s
== rhs
.s
&& lhs
.i
== rhs
.i
; }
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
107 struct StructWithDestructor
110 ~StructWithDestructor() {}
113 bool operator == ( StructWithDestructor
const& lhs
, StructWithDestructor
const& rhs
)
114 { return lhs
.i
== rhs
.i
; }
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
123 struct StructWithVirtualFunction
126 virtual void VirtualFunction();
129 void StructWithVirtualFunction::VirtualFunction()
133 bool operator == ( StructWithVirtualFunction
const& lhs
, StructWithVirtualFunction
const& rhs
)
134 { return lhs
.i
== rhs
.i
; }
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
143 struct DerivedFromAggregatePODStruct
: AggregatePODStruct
145 DerivedFromAggregatePODStruct() : AggregatePODStruct() {}
149 // A struct that wraps an aggregate POD struct as data member.
151 struct AggregatePODStructWrapper
153 AggregatePODStructWrapper() : dataMember() {}
154 AggregatePODStruct dataMember
;
157 bool operator == ( AggregatePODStructWrapper
const& lhs
, AggregatePODStructWrapper
const& rhs
)
158 { return lhs
.dataMember
== rhs
.dataMember
; }
160 typedef unsigned char ArrayOfBytes
[256];
164 // A struct that allows testing whether the appropriate copy functions are called.
166 struct CopyFunctionCallTester
168 bool is_copy_constructed
;
169 bool is_assignment_called
;
171 CopyFunctionCallTester()
172 : is_copy_constructed(false), is_assignment_called(false) {}
174 CopyFunctionCallTester(const CopyFunctionCallTester
& )
175 : is_copy_constructed(true), is_assignment_called(false) {}
177 CopyFunctionCallTester
& operator=(const CopyFunctionCallTester
& )
179 is_assignment_called
= true ;
186 // A struct that allows testing whether its customized swap function is called.
188 struct SwapFunctionCallTester
190 bool is_custom_swap_called
;
193 SwapFunctionCallTester()
194 : is_custom_swap_called(false), data(0) {}
196 SwapFunctionCallTester(const SwapFunctionCallTester
& arg
)
197 : is_custom_swap_called(false), data(arg
.data
) {}
199 void swap(SwapFunctionCallTester
& arg
)
201 std::swap(data
, arg
.data
);
202 is_custom_swap_called
= true;
203 arg
.is_custom_swap_called
= true;
207 void swap(SwapFunctionCallTester
& lhs
, SwapFunctionCallTester
& rhs
)
215 void check_initialized_value ( T
const& y
)
217 T initializedValue
= boost::initialized_value
;
218 BOOST_CHECK ( y
== initializedValue
) ;
222 #if __BORLANDC__ == 0x582
223 void check_initialized_value( NonPOD
const& )
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() ;
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 &)'
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.
246 bool test ( T
const& y
, T
const& z
)
248 const boost::unit_test::counter_t counter_before_test
= boost::minimal_test::errors_counter();
250 check_initialized_value(y
);
252 boost::value_initialized
<T
> x
;
253 BOOST_CHECK ( y
== x
) ;
254 BOOST_CHECK ( y
== boost::get(x
) ) ;
256 static_cast<T
&>(x
) = z
;
258 BOOST_CHECK ( x
== z
) ;
260 boost::value_initialized
<T
> const x_c
;
261 BOOST_CHECK ( y
== x_c
) ;
262 BOOST_CHECK ( y
== boost::get(x_c
) ) ;
263 T
& x_c_ref
= const_cast<T
&>( boost::get(x_c
) ) ;
265 BOOST_CHECK ( x_c
== z
) ;
267 boost::value_initialized
<T
> const copy1
= x
;
268 BOOST_CHECK ( boost::get(copy1
) == boost::get(x
) ) ;
270 boost::value_initialized
<T
> copy2
;
272 BOOST_CHECK ( boost::get(copy2
) == boost::get(x
) ) ;
274 boost::shared_ptr
<boost::value_initialized
<T
> > ptr( new boost::value_initialized
<T
> );
275 BOOST_CHECK ( y
== *ptr
) ;
277 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
278 boost::value_initialized
<T
const> cx
;
279 BOOST_CHECK ( y
== cx
) ;
280 BOOST_CHECK ( y
== boost::get(cx
) ) ;
282 boost::value_initialized
<T
const> const cx_c
;
283 BOOST_CHECK ( y
== cx_c
) ;
284 BOOST_CHECK ( y
== boost::get(cx_c
) ) ;
287 return boost::minimal_test::errors_counter() == counter_before_test
;
290 int test_main(int, char **)
292 BOOST_CHECK ( test( 0,1234 ) ) ;
293 BOOST_CHECK ( test( 0.0,12.34 ) ) ;
294 BOOST_CHECK ( test( POD(0,0,0.0), POD('a',1234,56.78) ) ) ;
295 BOOST_CHECK ( test( NonPOD( std::string() ), NonPOD( std::string("something") ) ) ) ;
297 NonPOD
NonPOD_object( std::string("NonPOD_object") );
298 BOOST_CHECK ( test
<NonPOD
*>( 0, &NonPOD_object
) ) ;
300 AggregatePODStruct zeroInitializedAggregatePODStruct
= { 0.0f
, '\0', 0 };
301 AggregatePODStruct nonZeroInitializedAggregatePODStruct
= { 1.25f
, 'a', -1 };
302 BOOST_CHECK ( test(zeroInitializedAggregatePODStruct
, nonZeroInitializedAggregatePODStruct
) );
304 StringAndInt stringAndInt0
;
305 StringAndInt stringAndInt1
;
308 stringAndInt1
.s
= std::string("1");
309 BOOST_CHECK ( test(stringAndInt0
, stringAndInt1
) );
311 StructWithDestructor structWithDestructor0
;
312 StructWithDestructor structWithDestructor1
;
313 structWithDestructor0
.i
= 0;
314 structWithDestructor1
.i
= 1;
315 BOOST_CHECK ( test(structWithDestructor0
, structWithDestructor1
) );
317 StructWithVirtualFunction structWithVirtualFunction0
;
318 StructWithVirtualFunction structWithVirtualFunction1
;
319 structWithVirtualFunction0
.i
= 0;
320 structWithVirtualFunction1
.i
= 1;
321 BOOST_CHECK ( test(structWithVirtualFunction0
, structWithVirtualFunction1
) );
323 DerivedFromAggregatePODStruct derivedFromAggregatePODStruct0
;
324 DerivedFromAggregatePODStruct derivedFromAggregatePODStruct1
;
325 static_cast<AggregatePODStruct
&>(derivedFromAggregatePODStruct0
) = zeroInitializedAggregatePODStruct
;
326 static_cast<AggregatePODStruct
&>(derivedFromAggregatePODStruct1
) = nonZeroInitializedAggregatePODStruct
;
327 BOOST_CHECK ( test(derivedFromAggregatePODStruct0
, derivedFromAggregatePODStruct1
) );
329 AggregatePODStructWrapper aggregatePODStructWrapper0
;
330 AggregatePODStructWrapper aggregatePODStructWrapper1
;
331 aggregatePODStructWrapper0
.dataMember
= zeroInitializedAggregatePODStruct
;
332 aggregatePODStructWrapper1
.dataMember
= nonZeroInitializedAggregatePODStruct
;
333 BOOST_CHECK ( test(aggregatePODStructWrapper0
, aggregatePODStructWrapper1
) );
335 ArrayOfBytes zeroInitializedArrayOfBytes
= { 0 };
336 boost::value_initialized
<ArrayOfBytes
> valueInitializedArrayOfBytes
;
337 BOOST_CHECK (std::memcmp(get(valueInitializedArrayOfBytes
), zeroInitializedArrayOfBytes
, sizeof(ArrayOfBytes
)) == 0);
339 boost::value_initialized
<ArrayOfBytes
> valueInitializedArrayOfBytes2
;
340 valueInitializedArrayOfBytes2
= valueInitializedArrayOfBytes
;
341 BOOST_CHECK (std::memcmp(get(valueInitializedArrayOfBytes
), get(valueInitializedArrayOfBytes2
), sizeof(ArrayOfBytes
)) == 0);
343 boost::value_initialized
<CopyFunctionCallTester
> copyFunctionCallTester1
;
344 BOOST_CHECK ( ! get(copyFunctionCallTester1
).is_copy_constructed
);
345 BOOST_CHECK ( ! get(copyFunctionCallTester1
).is_assignment_called
);
347 boost::value_initialized
<CopyFunctionCallTester
> copyFunctionCallTester2
= boost::value_initialized
<CopyFunctionCallTester
>(copyFunctionCallTester1
);
348 BOOST_CHECK ( get(copyFunctionCallTester2
).is_copy_constructed
);
349 BOOST_CHECK ( ! get(copyFunctionCallTester2
).is_assignment_called
);
351 boost::value_initialized
<CopyFunctionCallTester
> copyFunctionCallTester3
;
352 copyFunctionCallTester3
= boost::value_initialized
<CopyFunctionCallTester
>(copyFunctionCallTester1
);
353 BOOST_CHECK ( ! get(copyFunctionCallTester3
).is_copy_constructed
);
354 BOOST_CHECK ( get(copyFunctionCallTester3
).is_assignment_called
);
356 boost::value_initialized
<SwapFunctionCallTester
> swapFunctionCallTester1
;
357 boost::value_initialized
<SwapFunctionCallTester
> swapFunctionCallTester2
;
358 get(swapFunctionCallTester1
).data
= 1;
359 get(swapFunctionCallTester2
).data
= 2;
360 boost::swap(swapFunctionCallTester1
, swapFunctionCallTester2
);
361 BOOST_CHECK( get(swapFunctionCallTester1
).data
== 2 );
362 BOOST_CHECK( get(swapFunctionCallTester2
).data
== 1 );
363 BOOST_CHECK( get(swapFunctionCallTester1
).is_custom_swap_called
);
364 BOOST_CHECK( get(swapFunctionCallTester2
).is_custom_swap_called
);
370 unsigned int expected_failures
= 0;