diff --git a/initialized_test.cpp b/initialized_test.cpp new file mode 100644 index 0000000..9380957 --- /dev/null +++ b/initialized_test.cpp @@ -0,0 +1,116 @@ +// Copyright 2010, Niels Dekker. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Test program for boost::initialized. +// +// 2 May 2010 (Created) Niels Dekker + +#include +#include + +#include + +namespace +{ + // Typical use case for boost::initialized: A generic class that + // holds a value of type T, which must be initialized by either + // value-initialization or direct-initialization. + template class key_value_pair + { + std::string m_key; + boost::initialized m_value; + public: + + // Value-initializes the object held by m_value. + key_value_pair() { } + + // Value-initializes the object held by m_value. + explicit key_value_pair(const std::string& key) + : + m_key(key) + { + } + + // Direct-initializes the object held by m_value. + key_value_pair(const std::string& key, const T& value) + : + m_key(key), m_value(value) + { + } + + const T& get_value() const + { + return m_value; + } + }; + + + // Tells whether the argument is value-initialized. + bool is_value_initialized(const int& arg) + { + return arg == 0; + } + + + // Tells whether the argument is value-initialized. + bool is_value_initialized(const std::string& arg) + { + return arg.empty(); + } + + struct foo + { + int data; + }; + + bool operator==(const foo& lhs, const foo& rhs) + { + return lhs.data == rhs.data; + } + + + // Tells whether the argument is value-initialized. + bool is_value_initialized(const foo& arg) + { + return arg.data == 0; + } + + + template + void test_key_value_pair(const T& magic_value) + { + // The value component of a default key_value_pair must be value-initialized. + key_value_pair default_key_value_pair; + BOOST_TEST( is_value_initialized(default_key_value_pair.get_value() ) ); + + // The value component of a key_value_pair that only has its key explicitly specified + // must also be value-initialized. + BOOST_TEST( is_value_initialized(key_value_pair("key").get_value()) ); + + // However, the value component of the following key_value_pair must be + // "magic_value", as it must be direct-initialized. + BOOST_TEST( key_value_pair("key", magic_value).get_value() == magic_value ); + } +} + + +// Tests boost::initialize for a fundamental type, a type with a +// user-defined constructor, and a user-defined type without +// a user-defined constructor. +int main() +{ + + const int magic_number = 42; + test_key_value_pair(magic_number); + + const std::string magic_string = "magic value"; + test_key_value_pair(magic_string); + + const foo magic_foo = { 42 }; + test_key_value_pair(magic_foo); + + return boost::report_errors(); +} diff --git a/initialized_test_fail1.cpp b/initialized_test_fail1.cpp new file mode 100644 index 0000000..ffeecab --- /dev/null +++ b/initialized_test_fail1.cpp @@ -0,0 +1,33 @@ +// Copyright 2010, Niels Dekker. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Test program for boost::initialized. Must fail to compile. +// +// Initial: 2 May 2010 + +#include + +namespace +{ + void direct_initialize_from_int() + { + // Okay: initialized supports direct-initialization from T. + boost::initialized direct_initialized_int(1); + } + + void copy_initialize_from_int() + { + // The following line should not compile, because initialized + // was not intended to supports copy-initialization from T. + boost::initialized copy_initialized_int = 1; + } +} + +int main() +{ + // This should fail to compile, so there is no need to call any function. + return 0; +} diff --git a/initialized_test_fail2.cpp b/initialized_test_fail2.cpp new file mode 100644 index 0000000..f3fbf39 --- /dev/null +++ b/initialized_test_fail2.cpp @@ -0,0 +1,37 @@ +// Copyright 2010, Niels Dekker. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Test program for boost::initialized. Must fail to compile. +// +// Initial: 2 May 2010 + +#include + +namespace +{ + void from_value_initialized_to_initialized() + { + boost::value_initialized value_initialized_int; + + // Okay: initialized can be initialized by value_initialized. + boost::initialized initialized_int(value_initialized_int); + } + + void from_initialized_to_value_initialized() + { + boost::initialized initialized_int(13); + + // The following line should not compile, because initialized + // should not be convertible to value_initialized. + boost::value_initialized value_initialized_int(initialized_int); + } +} + +int main() +{ + // This should fail to compile, so there is no need to call any function. + return 0; +} diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3111cad..d3fc34c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,9 +32,13 @@ test-suite utility [ compile result_of_test.cpp ] [ run ../shared_iterator_test.cpp ] [ run ../value_init_test.cpp ] + [ run ../value_init_workaround_test.cpp ] + [ run ../initialized_test.cpp ] [ compile-fail ../value_init_test_fail1.cpp ] [ compile-fail ../value_init_test_fail2.cpp ] [ compile-fail ../value_init_test_fail3.cpp ] + [ compile-fail ../initialized_test_fail1.cpp ] + [ compile-fail ../initialized_test_fail2.cpp ] [ run ../verify_test.cpp ] ; diff --git a/value_init.htm b/value_init.htm index 57b2313..4ae9177 100644 --- a/value_init.htm +++ b/value_init.htm @@ -33,6 +33,7 @@ @@ -123,6 +124,12 @@ constructed by the following declaration:

+The template initialized +offers both value-initialization and direct-initialization. +It is especially useful as a data member type, allowing the very same object +to be either direct-initialized or value-initialized. +

+

The const object initialized_value allows value-initializing a variable as follows:

@@ -216,37 +223,65 @@ it may in practice still be left uninitialized, because of those
 compiler issues! It's hard to make a general statement on what those issues
 are like, because they depend on the compiler you are using, its version number,
 and the type of object you would like to have value-initialized.
-Compilers usually support value-initialization for built-in types properly.
-But objects of user-defined types that involve aggregates may in some cases
-be partially, or even entirely left uninitialized, when they should be value-initialized.
+All compilers we have tested so far support value-initialization for arithmetic types properly.
+However, various compilers may leave some types of aggregates uninitialized, when they 
+should be value-initialized. Value-initialization of objects of a pointer-to-member type may also
+go wrong on various compilers. 
 

-We have encountered issues regarding value-initialization on compilers by -Microsoft, Sun, Borland, and GNU. Here is a list of bug reports on those issues: - -
- -Microsoft Feedback ID 100744 - Value-initialization in new-expression -
Reported by Pavel Kuznetsov (MetaCommunications Engineering), 2005-07-28 -
- -GCC Bug 30111 - Value-initialization of POD base class doesn't initialize members -
Reported by Jonathan Wakely, 2006-12-07 -
- -GCC Bug 33916 - Default constructor fails to initialize array members -
Reported by Michael Elizabeth Chastain, 2007-10-26 -
- -Borland Report 51854 - Value-initialization: POD struct should be zero-initialized -
Reported by Niels Dekker (LKEB, Leiden University Medical Center), 2007-09-11 -
-
+At the moment of writing, May 2010, the following reported issues regarding +value-initialization are still there in current compiler releases: +

+Note that all known GCC issues regarding value-initialization are +fixed with GCC version 4.4, including +GCC Bug 30111. +Clang also has completely implemented value-initialization, as far as we know, +now that Clang Bug 7139 is fixed.

+ New versions of value_initialized (Boost release version 1.35 or higher) -offer a workaround to these issues: value_initialized will now clear -its internal data, prior to constructing the object that it contains. +offer a workaround to these issues: value_initialized may now clear +its internal data, prior to constructing the object that it contains. It will do +so for those compilers that need to have such a workaround, based on the +compiler defect macro BOOST_NO_COMPLETE_VALUE_INITIALIZATION.

Types and objects

@@ -340,6 +375,52 @@ the wrapped object is always performed with the get() idiom:

value_initialized<int> x ;
get(x) = 1 ; // OK

value_initialized<int const> cx ;
get(x) = 1 ; // ERROR: Cannot modify a const object

value_initialized<int> const x_c ;
get(x_c) = 1 ; // ERROR: Cannot modify a const object

value_initialized<int const> const cx_c ;
get(cx_c) = 1 ; // ERROR: Cannot modify a const object
+

template class initialized<T>

+ +
namespace boost {

template<class T>
class initialized
{ +
public : +
initialized() : x() {} +
explicit initialized(T const & arg) : x(arg) {} +
operator T const &() const; +
operator T&(); +
T const &data() const; +
T& data(); +
void swap( value_initialized<T>& ); +
+
private : +
unspecified x ; +
} ; +
+
template<class T> +
T const& get ( initialized<T> const& x ); +
+
template<class T> +
T& get ( initialized<T>& x ); +
+
} // namespace boost +
+ +The template class boost::initialized<T> supports both value-initialization +and direct-initialization, so its interface is a superset of the interface +of value_initialized<T>: Its default-constructor +value-initializes the wrapped object just like the default-constructor of +value_initialized<T>, but boost::initialized<T> +also offers an extra explicit +constructor, which direct-initializes the wrapped object by the specified value. +

+ +initialized<T> is especially useful when the wrapped +object must be either value-initialized or direct-initialized, depending on +runtime conditions. For example, initialized<T> could +hold the value of a data member that may be value-initialized by some +constructors, and direct-initialized by others. +On the other hand, if it is known beforehand that the +object must always be value-initialized, value_initialized<T> +may be preferable. And if the object must always be +direct-initialized, none of the two wrappers really needs to be used. +

+ +

initialized_value

@@ -399,6 +480,9 @@ Special thanks to Björn Karlsson who carefully edited and completed this do
 

value_initialized was reimplemented by Fernando Cacciola and Niels Dekker for Boost release version 1.35 (2008), offering a workaround to various compiler issues.

+

boost::initialized was very much inspired by feedback from Edward Diener and + Jeffrey Hellrung. +

initialized_value was written by Niels Dekker, and added to Boost release version 1.36 (2008).

Developed by Fernando Cacciola, @@ -407,9 +491,9 @@ for Boost release version 1.35 (2008), offering a workaround to various compiler


-

Revised 03 October 2009

+

Revised 30 May 2010

-

© Copyright Fernando Cacciola, 2002, 2009.

+

© Copyright Fernando Cacciola, 2002 - 2010.

Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt

diff --git a/value_init_workaround_test.cpp b/value_init_workaround_test.cpp new file mode 100644 index 0000000..190c267 --- /dev/null +++ b/value_init_workaround_test.cpp @@ -0,0 +1,144 @@ +// Copyright 2010, Niels Dekker. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Test program for the boost::value_initialized workaround. +// +// 17 June 2010 (Created) Niels Dekker + +// Switch the workaround off, before inluding "value_init.hpp". +#define BOOST_DETAIL_VALUE_INIT_WORKAROUND 0 +#include + +#include // For cout. +#include // For EXIT_SUCCESS and EXIT_FAILURE. + +namespace +{ + struct empty_struct + { + }; + + // A POD aggregate struct derived from an empty struct. + // Similar to struct Foo1 from Microsoft Visual C++ bug report 484295, + // "VC++ does not value-initialize members of derived classes without + // user-declared constructor", reported in 2009 by Sylvester Hesp: + // https://connect.microsoft.com/VisualStudio/feedback/details/484295 + struct derived_struct: empty_struct + { + int data; + }; + + bool is_value_initialized(const derived_struct& arg) + { + return arg.data == 0; + } + + + class virtual_destructor_holder + { + public: + int i; + virtual ~virtual_destructor_holder() + { + } + }; + + bool is_value_initialized(const virtual_destructor_holder& arg) + { + return arg.i == 0; + } + + // Equivalent to the Stats class from GCC Bug 33916, + // "Default constructor fails to initialize array members", reported in 2007 by + // Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916 + // and fixed for GCC 4.2.4. + class private_int_array_pair + { + friend bool is_value_initialized(const private_int_array_pair& arg); + private: + int first[12]; + int second[12]; + }; + + bool is_value_initialized(const private_int_array_pair& arg) + { + for ( unsigned i = 0; i < 12; ++i) + { + if ( (arg.first[i] != 0) || (arg.second[i] != 0) ) + { + return false; + } + } + return true; + } + + template + bool is_value_initialized(const T(& arg)[2]) + { + return + is_value_initialized(arg[0]) && + is_value_initialized(arg[1]); + } + + template + bool is_value_initialized(const boost::value_initialized& arg) + { + return is_value_initialized(arg.data()); + } + + // Returns zero when the specified object is value-initializated, and one otherwise. + // Prints a message to standard output if the value-initialization has failed. + template + unsigned failed_to_value_initialized(const T& object, const char *const object_name) + { + if ( is_value_initialized(object) ) + { + return 0u; + } + else + { + std::cout << "Note: Failed to value-initialize " << object_name << '.' << std::endl; + return 1u; + } + } + +// A macro that passed both the name and the value of the specified object to +// the function above here. +#define FAILED_TO_VALUE_INITIALIZE(value) failed_to_value_initialized(value, #value) + + // Equivalent to the dirty_stack() function from GCC Bug 33916, + // "Default constructor fails to initialize array members", reported in 2007 by + // Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916 + void dirty_stack() + { + unsigned char array_on_stack[4096]; + for (unsigned i = 0; i < sizeof(array_on_stack); ++i) + { + array_on_stack[i] = 0x11; + } + } + +} + + +int main() +{ + dirty_stack(); + + // TODO More types may be added later. + const unsigned num_failures = + FAILED_TO_VALUE_INITIALIZE(boost::value_initialized()) + + FAILED_TO_VALUE_INITIALIZE(boost::value_initialized()) + + FAILED_TO_VALUE_INITIALIZE(boost::value_initialized()); + +#ifdef BOOST_DETAIL_VALUE_INIT_WORKAROUND_SUGGESTED + // One or more failures are expected. + return num_failures > 0 ? EXIT_SUCCESS : EXIT_FAILURE; +#else + // No failures are expected. + return num_failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +#endif +}