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