Skip to content

Commit

Permalink
Fixed errors in singleton
Browse files Browse the repository at this point in the history
removed superfluous comma to avoid warning
  • Loading branch information
robertramey committed Nov 9, 2018
1 parent efcd46e commit f297d80
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 37 deletions.
8 changes: 4 additions & 4 deletions include/boost/archive/impl/archive_serializer_map.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ archive_serializer_map<Archive>::insert(const basic_serializer * bs){
template<class Archive>
BOOST_ARCHIVE_OR_WARCHIVE_DECL void
archive_serializer_map<Archive>::erase(const basic_serializer * bs){
BOOST_ASSERT(! boost::serialization::singleton<
extra_detail::map<Archive>
>::is_destroyed()
);
// note: previously this conditional was a runtime assertion with
// BOOST_ASSERT. We've changed it because we've discovered that at
// least one platform is not guaranteed to destroy singletons in
// reverse order of distruction.
if(boost::serialization::singleton<
extra_detail::map<Archive>
>::is_destroyed())
Expand Down
99 changes: 69 additions & 30 deletions include/boost/serialization/singleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// Copyright Robert Ramey 2007. Changes made to permit
// application throughout the serialization library.
//
// Copyright Alexander Grund 2018. Corrections to singleton lifetime
//
// 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)
Expand All @@ -32,7 +34,7 @@
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif
#endif

#include <boost/assert.hpp>
#include <boost/config.hpp>
Expand All @@ -48,8 +50,8 @@
# pragma warning(disable : 4511 4512)
#endif

namespace boost {
namespace serialization {
namespace boost {
namespace serialization {

//////////////////////////////////////////////////////////////////////
// Provides a dynamically-initialized (singleton) instance of T in a
Expand All @@ -58,7 +60,7 @@ namespace serialization {
// details.
//

// singletons created by this code are guarenteed to be unique
// Singletons created by this code are guaranteed to be unique
// within the executable or shared library which creates them.
// This is sufficient and in fact ideal for the serialization library.
// The singleton is created when the module is loaded and destroyed
Expand All @@ -74,14 +76,22 @@ namespace serialization {
// Second, it provides a mechanism to detect when a non-const function
// is called after initialization.

// make a singleton to lock/unlock all singletons for alteration.
// Make a singleton to lock/unlock all singletons for alteration.
// The intent is that all singletons created/used by this code
// are to be initialized before main is called. A test program
// can lock all the singletons when main is entereed. This any
// attempt to retieve a mutable instances while locked will
// generate a assertion if compiled for debug.

// note usage of BOOST_DLLEXPORT. These functions are in danger of
// can lock all the singletons when main is entered. Thus any
// attempt to retrieve a mutable instance while locked will
// generate an assertion if compiled for debug.

// The singleton template can be used in 2 ways:
// 1 (Recommended): Publicly inherit your type T from singleton<T>,
// make its ctor protected and access it via T::get_const_instance()
// 2: Simply access singleton<T> without changing T. Note that this only
// provides a global instance accesible by singleton<T>::get_const_instance()
// or singleton<T>::get_mutable_instance() to prevent using multiple instances
// of T make its ctor protected

// Note on usage of BOOST_DLLEXPORT: These functions are in danger of
// being eliminated by the optimizer when building an application in
// release mode. Usage of the macro is meant to signal the compiler/linker
// to avoid dropping these functions which seem to be unreferenced.
Expand Down Expand Up @@ -113,34 +123,67 @@ static inline singleton_module & get_singleton_module(){
return m;
}

namespace detail {

// This is the class actually instantiated and hence the real singleton.
// So there will only be one instance of this class. This does not hold
// for singleton<T> as a class derived from singleton<T> could be
// instantiated multiple times.
// It also provides a flag `is_destroyed` which returns true, when the
// class was destructed. It is static and hence accesible even after
// destruction. This can be used to check, if the singleton is still
// accesible e.g. in destructors of other singletons.
template<class T>
class singleton_wrapper : public T
{
static bool & get_is_destroyed(){
// Prefer a static function member to avoid LNK1179.
// Note: As this is for a singleton (1 instance only) it must be set
// never be reset (to false)!
static bool is_destroyed_flag = false;
return is_destroyed_flag;
}
public:
singleton_wrapper(){
BOOST_ASSERT(! is_destroyed());
}
~singleton_wrapper(){
get_is_destroyed() = true;
}
static bool is_destroyed(){
return get_is_destroyed();
}
};

} // detail

template <class T>
class singleton {
private:
// note presumption that T has a default constructor
static T & m_instance;
static T * m_instance;
// include this to provoke instantiation at pre-execution time
static void use(T const &) {}
static T & get_instance() {
static T t;

// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! is_destroyed());

// use a wrapper so that types T with protected constructors can be used
// Using a static function member avoids LNK1179
static detail::singleton_wrapper< T > t;

// note that the following is absolutely essential.
// commenting out this statement will cause compilers to fail to
// construct the instance at pre-execution time. This would prevent
// our usage/implementation of "locking" and introduce uncertainty into
// the sequence of object initializaition.
use(m_instance);
// the sequence of object initialization.
use(* m_instance);

return static_cast<T &>(t);
}
protected:
// Do not allow instantiation of a singleton<T>. But we want to allow
// `class T: public singleton<T>` so we can't delete this ctor
BOOST_DLLEXPORT singleton(){}

static bool & get_is_destroyed(){
static bool is_destroyed;
return is_destroyed;
}
public:
BOOST_DLLEXPORT static T & get_mutable_instance(){
BOOST_ASSERT(! get_singleton_module().is_locked());
Expand All @@ -150,18 +193,14 @@ class singleton {
return get_instance();
}
BOOST_DLLEXPORT static bool is_destroyed(){
return get_is_destroyed();
}
BOOST_DLLEXPORT singleton(){
get_is_destroyed() = false;
}
BOOST_DLLEXPORT ~singleton() {
get_is_destroyed() = true;
return detail::singleton_wrapper< T >::is_destroyed();
}
};

// Assigning the instance reference to a static member forces initialization
// at startup time as described in http://tinyurl.com/ljdp8
template<class T>
T & singleton< T >::m_instance = singleton< T >::get_instance();
T * singleton< T >::m_instance = & singleton< T >::get_instance();

} // namespace serialization
} // namespace boost
Expand Down
5 changes: 4 additions & 1 deletion src/extended_type_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ BOOST_SERIALIZATION_DECL void
extended_type_info::key_unregister() const{
if(NULL == get_key())
return;
BOOST_ASSERT(! singleton<detail::ktmap>::is_destroyed());
// note: it's been discovered that at least one platform is not guaranteed
// to destroy singletons reverse order of construction. So we can't
// use a runtime assert here. Leave this in a reminder not to do this!
// BOOST_ASSERT(! singleton<detail::ktmap>::is_destroyed());
if(! singleton<detail::ktmap>::is_destroyed()){
detail::ktmap & x = singleton<detail::ktmap>::get_mutable_instance();
detail::ktmap::iterator start = x.lower_bound(this);
Expand Down
6 changes: 5 additions & 1 deletion src/extended_type_info_typeid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ BOOST_SERIALIZATION_DECL void
extended_type_info_typeid_0::type_unregister()
{
if(NULL != m_ti){
BOOST_ASSERT(! singleton<tkmap>::is_destroyed());
// note: previously this conditional was a runtime assertion with
// BOOST_ASSERT. We've changed it because we've discovered that at
// least one platform is not guaranteed to destroy singletons in
// reverse order of distruction.
// BOOST_ASSERT(! singleton<tkmap>::is_destroyed());
if(! singleton<tkmap>::is_destroyed()){
tkmap & x = singleton<tkmap>::get_mutable_instance();

Expand Down
2 changes: 1 addition & 1 deletion test/A.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ void A::serialize(
#ifndef BOOST_NO_STD_WSTRING
ar & BOOST_SERIALIZATION_NVP(z);
#endif
};
}

0 comments on commit f297d80

Please sign in to comment.