1 // Copyright 2010, Niels Dekker.
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 the boost::value_initialized<T> workaround.
8 //
9 // 17 June 2010 (Created) Niels Dekker
10
11 #include <boost/utility/value_init.hpp>
12 #include <boost/core/lightweight_test.hpp>
13 #include <boost/config/workaround.hpp>
14 #include <iostream>
15
16 namespace
17 {
18 struct empty_struct
19 {
20 };
21
22 // A POD aggregate struct derived from an empty struct.
23 // Similar to struct Foo1 from Microsoft Visual C++ bug report 484295,
24 // "VC++ does not value-initialize members of derived classes without
25 // user-declared constructor", reported in 2009 by Sylvester Hesp:
26 // https://connect.microsoft.com/VisualStudio/feedback/details/484295
27 struct derived_struct: empty_struct
28 {
29 int data;
30 };
31
is_value_initialized(const derived_struct & arg)32 bool is_value_initialized(const derived_struct& arg)
33 {
34 return arg.data == 0;
35 }
36
37
38 class virtual_destructor_holder
39 {
40 public:
41 int i;
~virtual_destructor_holder()42 virtual ~virtual_destructor_holder()
43 {
44 }
45 };
46
is_value_initialized(const virtual_destructor_holder & arg)47 bool is_value_initialized(const virtual_destructor_holder& arg)
48 {
49 return arg.i == 0;
50 }
51
52 // Equivalent to the Stats class from GCC Bug 33916,
53 // "Default constructor fails to initialize array members", reported in 2007 by
54 // Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916
55 // and fixed for GCC 4.2.4.
56 class private_int_array_pair
57 {
58 friend bool is_value_initialized(const private_int_array_pair& arg);
59 private:
60 int first[12];
61 int second[12];
62 };
63
is_value_initialized(const private_int_array_pair & arg)64 bool is_value_initialized(const private_int_array_pair& arg)
65 {
66 for ( unsigned i = 0; i < 12; ++i)
67 {
68 if ( (arg.first[i] != 0) || (arg.second[i] != 0) )
69 {
70 return false;
71 }
72 }
73 return true;
74 }
75
76 struct int_pair_struct
77 {
78 int first;
79 int second;
80 };
81
82 typedef int int_pair_struct::*ptr_to_member_type;
83
84 struct ptr_to_member_struct
85 {
86 ptr_to_member_type data;
87 };
88
is_value_initialized(const ptr_to_member_struct & arg)89 bool is_value_initialized(const ptr_to_member_struct& arg)
90 {
91 return arg.data == 0;
92 }
93
94 template <typename T>
is_value_initialized(const T (& arg)[2])95 bool is_value_initialized(const T(& arg)[2])
96 {
97 return
98 is_value_initialized(arg[0]) &&
99 is_value_initialized(arg[1]);
100 }
101
102 template <typename T>
is_value_initialized(const boost::value_initialized<T> & arg)103 bool is_value_initialized(const boost::value_initialized<T>& arg)
104 {
105 return is_value_initialized(arg.data());
106 }
107
108 // Returns zero when the specified object is value-initializated, and one otherwise.
109 // Prints a message to standard output if the value-initialization has failed.
110 template <class T>
failed_to_value_initialized(const T & object,const char * const object_name)111 unsigned failed_to_value_initialized(const T& object, const char *const object_name)
112 {
113 if ( is_value_initialized(object) )
114 {
115 return 0u;
116 }
117 else
118 {
119 std::cout << "Note: Failed to value-initialize " << object_name << '.' << std::endl;
120 return 1u;
121 }
122 }
123
124 // A macro that passed both the name and the value of the specified object to
125 // the function above here.
126 #define FAILED_TO_VALUE_INITIALIZE(value) failed_to_value_initialized(value, #value)
127
128 // Equivalent to the dirty_stack() function from GCC Bug 33916,
129 // "Default constructor fails to initialize array members", reported in 2007 by
130 // Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916
dirty_stack()131 void dirty_stack()
132 {
133 unsigned char array_on_stack[4096];
134 for (unsigned i = 0; i < sizeof(array_on_stack); ++i)
135 {
136 array_on_stack[i] = 0x11;
137 }
138 }
139
140 }
141
142
main()143 int main()
144 {
145 #ifdef BOOST_DETAIL_VALUE_INIT_WORKAROUND_SUGGESTED
146
147 std::cout << "BOOST_DETAIL_VALUE_INIT_WORKAROUND_SUGGESTED is defined.\n\n";
148
149 #endif
150
151 dirty_stack();
152
153 BOOST_TEST( is_value_initialized( boost::value_initialized<derived_struct>() ) );
154 BOOST_TEST( is_value_initialized( boost::value_initialized<virtual_destructor_holder[2]>() ) );
155 BOOST_TEST( is_value_initialized( boost::value_initialized<private_int_array_pair>() ) );
156
157 #if !BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1925) )
158
159 // Null pointers to data members are represented as -1 in MSVC, but
160 // value initialization sets them to all zero. The workaround employed
161 // by value_initialized<> is to memset the storage to all zero, which
162 // doesn't help.
163
164 BOOST_TEST( is_value_initialized( boost::value_initialized<ptr_to_member_struct>() ) );
165
166 #endif
167
168 return boost::report_errors();
169 }
170