1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 2 // test_singleton_inherited.cpp: 3 // Test the singleton class for a "inherited" singleton (used as Foo:public singleton<Foo>) 4 // This can be uses as singleton<Foo>::get_const_instance() OR Foo::get_const_instance() 5 // 6 // - is_destroyed returns false when singleton is active or uninitialized 7 // - is_destroyed returns true when singleton is destructed 8 // - the singleton is eventually destructed (no memory leak) 9 10 // (C) Copyright 2018 Alexander Grund 11 // Use, modification and distribution is subject to the Boost Software 12 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 13 // http://www.boost.org/LICENSE_1_0.txt) 14 15 #include "test_tools.hpp" 16 #include <boost/serialization/singleton.hpp> 17 #include <boost/preprocessor/stringize.hpp> 18 #include <stdexcept> 19 20 // Can't use BOOST_TEST because: 21 // a) destructors are called after program exit 22 // b) This is intended to be used by shared libraries too which would then need their own report_errors call 23 // We halso have to disable the Wterminate warning as we call this from dtors 24 // C++ will terminate the program in such cases which is OK here 25 #pragma GCC diagnostic push 26 #pragma GCC diagnostic ignored "-Wterminate" 27 #define THROW_ON_FALSE(cond) if(!(cond)) throw std::runtime_error(__FILE__ "(" BOOST_PP_STRINGIZE(__LINE__) ") Assertion failed: " #cond) 28 29 // Enum to designate the state of the singletonized instances 30 enum ConstructionState{CS_UNINIT, CS_INIT, CS_DESTROYED}; 31 32 // We need another singleton to check for the destruction of the singletons at program exit 33 // We don't need all the magic for shared library anti-optimization and can keep it very simple 34 struct controller{ getInstancecontroller35 static controller& getInstance(){ 36 static controller instance; 37 return instance; 38 } 39 ConstructionState state; 40 private: controllercontroller41 controller() { 42 state = CS_UNINIT; 43 } 44 ~controller(); 45 }; 46 47 // A simple class that sets its construction state in the controller singleton 48 struct Foo: boost::serialization::singleton<Foo>{ FooFoo49 Foo(): i(42) { 50 // access controller singleton. Therefore controller will be constructed before this 51 THROW_ON_FALSE(controller::getInstance().state == CS_UNINIT); 52 controller::getInstance().state = CS_INIT; 53 } ~FooFoo54 ~Foo() { 55 // Because controller is constructed before this, it will be destructed AFTER this. Hence controller is still valid 56 THROW_ON_FALSE(controller::getInstance().state == CS_INIT); 57 controller::getInstance().state = CS_DESTROYED; 58 } 59 // Volatile to prevent compiler optimization from removing this 60 volatile int i; 61 }; 62 ~controller()63controller::~controller() { 64 // If this fails, the singletons were not freed and memory is leaked 65 THROW_ON_FALSE(state == CS_DESTROYED); 66 // If this fails, then the destroyed flag is not set and one may use a deleted instance if relying on this flag 67 THROW_ON_FALSE(boost::serialization::singleton<Foo>::is_destroyed()); 68 THROW_ON_FALSE(Foo::is_destroyed()); 69 } 70 71 int test_main(int,char * [])72test_main( int /* argc */, char* /* argv */[] ) 73 { 74 // Check if the singleton is alive and use it 75 BOOST_CHECK(!boost::serialization::singleton<Foo>::is_destroyed()); 76 BOOST_CHECK(!Foo::is_destroyed()); 77 78 BOOST_CHECK(boost::serialization::singleton<Foo>::get_const_instance().i == 42); 79 BOOST_CHECK(Foo::get_const_instance().i == 42); 80 return EXIT_SUCCESS; 81 } 82