Best way to create a class using the singleton pattern and shared pointers?

Here is a function that I am trying to understand why its giving me a error via valgrind of "Invalid read of size 4". 16: Trace_State::ptr_t Trace_State::Instance() 17: { 18: // Lock the resource? 19: if ( m_instance.get() == 0 ) 20: { 21: m_instance = Trace_State::ptr_t ( new Trace_State() ); 22: } 23: 24: // Unlock the resource? 25: 26: return m_instance; 27: } When I look at the full error report I see: ==10721== Invalid read of size 4 ==10721== at 0x41682E3: boost::detail::atomic_increment(int*) (sp_counted_base_gcc_x86.hpp:66) ==10721== by 0x4168359: boost::detail::sp_counted_base::add_ref_copy() (sp_counted_base_gcc_x86.hpp:133) ==10721== by 0x41684B1: boost::detail::shared_count::shared_count(boost::detail::shared_count const&) (shared_count.hpp:170) ==10721== by 0x41775CF: boost::shared_ptr<libreverse::trace::Trace_State>::shared_ptr(boost::shared_ptr<libreverse::trace::Trace_State> const&) (shared_ptr.hpp:106) ==10721== by 0x41772F0: libreverse::trace::Trace_State::Instance() (Trace.cpp:26) ==10721== by 0x417731B: libreverse::trace::Trace::write_Trace(unsigned, std::string) (Trace.cpp:180) ==10721== by 0x425E394: libreverse::elf_module::Elf_Reader<32>::~Elf_Reader() (Elf_Reader_T.cpp:52) ==10721== by 0x423C8FD: void boost::checked_delete<libreverse::elf_module::Elf_Reader<32> >(libreverse::elf_module::Elf_Reader<32>*) (checked_delete.hpp:34) ==10721== by 0x42480B8: boost::detail::sp_counted_impl_p<libreverse::elf_module::Elf_Reader<32> >::dispose() (sp_counted_impl.hpp:76) ==10721== by 0x804C207: boost::detail::sp_counted_base::release() (sp_counted_base_gcc_x86.hpp:145) ==10721== by 0x804C231: boost::detail::shared_count::~shared_count() (shared_count.hpp:159) ==10721== by 0x423C171: boost::shared_ptr<libreverse::io::File_Reader>::~shared_ptr() (shared_ptr.hpp:106) ==10721== Address 0x43F7A44 is 12 bytes inside a block of size 24 free'd ==10721== at 0x40050FF: free (vg_replace_malloc.c:233) ==10721== by 0x4185AC5: operator delete(void*) (sp_debug_hooks.cpp:205) ==10721== by 0x417C9A4: boost::detail::sp_counted_impl_p<libreverse::trace::Trace_State>::~sp_counted_impl_p() (sp_counted_impl.hpp:52) ==10721== by 0x4168337: boost::detail::sp_counted_base::destroy() (sp_counted_base_gcc_x86.hpp:126) ==10721== by 0x804C1CD: boost::detail::sp_counted_base::weak_release() (sp_counted_base_gcc_x86.hpp:159) ==10721== by 0x804C212: boost::detail::sp_counted_base::release() (sp_counted_base_gcc_x86.hpp:146) ==10721== by 0x804C231: boost::detail::shared_count::~shared_count() (shared_count.hpp:159) ==10721== by 0x4168EBB: boost::shared_ptr<libreverse::trace::Trace_State>::~shared_ptr() (shared_ptr.hpp:106) ==10721== by 0x4176711: __tcf_1 (Trace.cpp:14) ==10721== by 0x47BDCBE8: __cxa_finalize (in /lib/libc-2.5.so) ==10721== by 0x4167192: (within /usr/local/lib/libreverse.so.0.0.0) ==10721== by 0x429EE3B: (within /usr/local/lib/libreverse.so.0.0.0) ==10721== The error is coming when the return of the Trace boost shared ptr. I am wondering if I have made an error in the creation of the class. Here is how the class is defined: #ifndef LIBREVERSE_TRACE_H #define LIBREVERSE_TRACE_H #include <boost/cstdint.hpp> #include <boost/shared_ptr.hpp> #include <fstream> #include "Reverse.h" namespace libreverse { namespace trace { /* Idea taken from http://www.codeproject.com/debug/xytrace.asp * (28 Jan 2002 - Xiangyang Liu) * * I have modified this so that we don't use varargs and use constant types */ class Trace_State { public: typedef boost::shared_ptr<Trace_State> ptr_t; virtual ~Trace_State(); static Trace_State::ptr_t Instance(); void set_Trace_File_Prefix ( std::string name ); void set_Trace_Level ( boost::uint32_t level ); void open_Trace_File ( void ); std::string get_ID_String ( void ); void close_Trace_File ( void ); boost::uint32_t get_Trace_Level ( void ) const; void write_Message ( boost::uint32_t level, std::string msg ); private: Trace_State(); static Trace_State::ptr_t m_instance; std::string m_file_prefix; boost::uint32_t m_trace_level; //boost::recursive_mutex m_mutex; std::ofstream m_log_stream; }; class Trace { public: static bool write_Trace ( boost::uint32_t level, std::string message ); }; } /* namespace trace */ } /* namespace libreverse */ #endif /* LIBREVERSE_TRACE_H */ Is this an appropriate way to create a class using the singleton pattern? Is the constructor assigning the boost shared_ptr? Stephen

-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: 16 May 2007 23:52 To: boost-users Subject: [Boost-users] Best way to create a class using the singletonpattern and shared pointers?
Here is a function that I am trying to understand why its giving me a error via valgrind of "Invalid read of size 4".
16: Trace_State::ptr_t Trace_State::Instance() 17: { 18: // Lock the resource? 19: if ( m_instance.get() == 0 ) 20: { 21: m_instance = Trace_State::ptr_t ( new Trace_State() ); 22: } 23: 24: // Unlock the resource? 25: 26: return m_instance; 27: }
When I look at the full error report I see:
==10721== Invalid read of size 4 ==10721== at 0x41682E3: boost::detail::atomic_increment(int*) (sp_counted_base_gcc_x86.hpp:66) ==10721== by 0x4168359: boost::detail::sp_counted_base::add_ref_copy() (sp_counted_base_gcc_x86.hpp:133) ==10721== by 0x41684B1: boost::detail::shared_count::shared_count(boost::detail::share d_count const&) (shared_count.hpp:170) ==10721== by 0x41775CF: boost::shared_ptr<libreverse::trace::Trace_State>::shared_ptr( boost::shared_ptr<libreverse::trace::Trace_State> const&) (shared_ptr.hpp:106) ==10721== by 0x41772F0: libreverse::trace::Trace_State::Instance() (Trace.cpp:26) ==10721== by 0x417731B: libreverse::trace::Trace::write_Trace(unsigned, std::string) (Trace.cpp:180) ==10721== by 0x425E394: libreverse::elf_module::Elf_Reader<32>::~Elf_Reader() (Elf_Reader_T.cpp:52) ==10721== by 0x423C8FD: void boost::checked_delete<libreverse::elf_module::Elf_Reader<32>
(libreverse::elf_module::Elf_Reader<32>*) (checked_delete.hpp:34) ==10721== by 0x42480B8: boost::detail::sp_counted_impl_p<libreverse::elf_module::Elf_R eader<32> >::dispose() (sp_counted_impl.hpp:76) ==10721== by 0x804C207: boost::detail::sp_counted_base::release() (sp_counted_base_gcc_x86.hpp:145) ==10721== by 0x804C231: boost::detail::shared_count::~shared_count() (shared_count.hpp:159) ==10721== by 0x423C171: boost::shared_ptr<libreverse::io::File_Reader>::~shared_ptr() (shared_ptr.hpp:106) ==10721== Address 0x43F7A44 is 12 bytes inside a block of size 24 free'd ==10721== at 0x40050FF: free (vg_replace_malloc.c:233) ==10721== by 0x4185AC5: operator delete(void*) (sp_debug_hooks.cpp:205) ==10721== by 0x417C9A4: boost::detail::sp_counted_impl_p<libreverse::trace::Trace_Stat e>::~sp_counted_impl_p() (sp_counted_impl.hpp:52) ==10721== by 0x4168337: boost::detail::sp_counted_base::destroy() (sp_counted_base_gcc_x86.hpp:126) ==10721== by 0x804C1CD: boost::detail::sp_counted_base::weak_release() (sp_counted_base_gcc_x86.hpp:159) ==10721== by 0x804C212: boost::detail::sp_counted_base::release() (sp_counted_base_gcc_x86.hpp:146) ==10721== by 0x804C231: boost::detail::shared_count::~shared_count() (shared_count.hpp:159) ==10721== by 0x4168EBB: boost::shared_ptr<libreverse::trace::Trace_State>::~shared_ptr () (shared_ptr.hpp:106) ==10721== by 0x4176711: __tcf_1 (Trace.cpp:14) ==10721== by 0x47BDCBE8: __cxa_finalize (in /lib/libc-2.5.so) ==10721== by 0x4167192: (within /usr/local/lib/libreverse.so.0.0.0) ==10721== by 0x429EE3B: (within /usr/local/lib/libreverse.so.0.0.0) ==10721==
The error is coming when the return of the Trace boost shared ptr. I am wondering if I have made an error in the creation of the class. Here is how the class is defined:
#ifndef LIBREVERSE_TRACE_H #define LIBREVERSE_TRACE_H
#include <boost/cstdint.hpp> #include <boost/shared_ptr.hpp> #include <fstream> #include "Reverse.h"
namespace libreverse { namespace trace {
/* Idea taken from http://www.codeproject.com/debug/xytrace.asp * (28 Jan 2002 - Xiangyang Liu) * * I have modified this so that we don't use varargs and use constant types */ class Trace_State { public:
typedef boost::shared_ptr<Trace_State> ptr_t;
virtual ~Trace_State();
static Trace_State::ptr_t Instance();
void set_Trace_File_Prefix ( std::string name );
void set_Trace_Level ( boost::uint32_t level );
void open_Trace_File ( void );
std::string get_ID_String ( void );
void close_Trace_File ( void );
boost::uint32_t get_Trace_Level ( void ) const;
void write_Message ( boost::uint32_t level, std::string msg );
private:
Trace_State();
static Trace_State::ptr_t m_instance;
std::string m_file_prefix;
boost::uint32_t m_trace_level;
//boost::recursive_mutex m_mutex;
std::ofstream m_log_stream; };
class Trace { public:
static bool write_Trace ( boost::uint32_t level, std::string message ); };
} /* namespace trace */ } /* namespace libreverse */
#endif /* LIBREVERSE_TRACE_H */
Is this an appropriate way to create a class using the singleton pattern? Is the constructor assigning the boost shared_ptr?
Stephen
Sorry, I don't have an answer to your specific question, but why would you need to use a shared_ptr on a singleton anyway? You have no real need to deallocate a singleton instance, so no need for a shared_ptr....perhaps use a reference (See Meyers singletons) Oh, hold on a sec....is it valid to call get() on an unassigned shared_ptr, which you are doing in the instance function? James
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
This message (including any attachments) contains confidential and/or proprietary information intended only for the addressee. Any unauthorized disclosure, copying, distribution or reliance on the contents of this information is strictly prohibited and may constitute a violation of law. If you are not the intended recipient, please notify the sender immediately by responding to this e-mail, and delete the message from your system. If you have any questions about this e-mail please notify the sender immediately.

On Thu, 2007-05-17 at 11:16 +0200, Hughes, James wrote:
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: 16 May 2007 23:52 To: boost-users Subject: [Boost-users] Best way to create a class using the singletonpattern and shared pointers?
Here is a function that I am trying to understand why its giving me a error via valgrind of "Invalid read of size 4".
16: Trace_State::ptr_t Trace_State::Instance() 17: { 18: // Lock the resource? 19: if ( m_instance.get() == 0 ) 20: { 21: m_instance = Trace_State::ptr_t ( new Trace_State() ); 22: } 23: 24: // Unlock the resource? 25: 26: return m_instance; 27: }
Sorry, I don't have an answer to your specific question, but why would you need to use a shared_ptr on a singleton anyway? You have no real need to deallocate a singleton instance, so no need for a shared_ptr....perhaps use a reference (See Meyers singletons)
Oh, hold on a sec....is it valid to call get() on an unassigned shared_ptr, which you are doing in the instance function?
James
Back when I first learned about the singleton pattern I used a standard pointer similar to this example: class Singleton { public: static Singleton* Instance(); protected: Singleton(); Singleton(const Singleton&); Singleton& operator= (const Singleton&); private: static Singleton* pinstance; }; Now I am trying to be a good programmer and keep track of my pointers. So I decided that I should replace the pointer with a shared_ptr. In regards to the validity of calling get() on an unassigned shared_ptr I thought that if a shared_ptr was declared in the header and no call is given to any constructor that the default constructor would be used. Therefore the shared_ptr would have a value of 0x0. Stephen

snip
Sorry, I don't have an answer to your specific question,
but why would
you need to use a shared_ptr on a singleton anyway? You have no real need to deallocate a singleton instance, so no need for a shared_ptr....perhaps use a reference (See Meyers singletons)
Oh, hold on a sec....is it valid to call get() on an unassigned shared_ptr, which you are doing in the instance function?
James
Back when I first learned about the singleton pattern I used a standard pointer similar to this example:
class Singleton { public: static Singleton* Instance(); protected: Singleton(); Singleton(const Singleton&); Singleton& operator= (const Singleton&); private: static Singleton* pinstance; };
Now I am trying to be a good programmer and keep track of my pointers. So I decided that I should replace the pointer with a shared_ptr.
In regards to the validity of calling get() on an unassigned shared_ptr I thought that if a shared_ptr was declared in the header and no call is given to any constructor that the default constructor would be used. Therefore the shared_ptr would have a value of 0x0.
Stephen
Wasn't sure about the get(), but with regard to the singleton itself, there is no real need to deallocate the singleton instance as the only memory leak is at the termination of the program and the memory is aonly allocated once, so there is no need to reference count the people using the singleton (which would be the purpose of the shared_ptr). I'd just be inclined to either use your original code, or go with the Meyers singleton which returns a reference (no pointers at all). Just take care if multi threaded. James This message (including any attachments) contains confidential and/or proprietary information intended only for the addressee. Any unauthorized disclosure, copying, distribution or reliance on the contents of this information is strictly prohibited and may constitute a violation of law. If you are not the intended recipient, please notify the sender immediately by responding to this e-mail, and delete the message from your system. If you have any questions about this e-mail please notify the sender immediately.

On Thu, 2007-05-17 at 16:57 +0200, Hughes, James wrote:
Wasn't sure about the get(), but with regard to the singleton itself, there is no real need to deallocate the singleton instance as the only memory leak is at the termination of the program and the memory is aonly allocated once, so there is no need to reference count the people using the singleton (which would be the purpose of the shared_ptr). I'd just be inclined to either use your original code, or go with the Meyers singleton which returns a reference (no pointers at all). Just take care if multi threaded.
James
Right now the application is single threaded. I did that to keep things simple. Its fast enough right now being designed that way. I will look at the Meyers singleton. Thanks. Stephen

Here is the latest form using what I believe is the Meyer form of the singleton. What I was using earlier was from the GoF book on patterns. They use a pointer and instead of a static variable. I would appreciate any comments on this code. The intent is to provide a single-threaded tracing capability which is logged to a file. ----------- HEADER ----------------- #ifndef LIBREVERSE_TRACE_H #define LIBREVERSE_TRACE_H #include <boost/cstdint.hpp> #include <boost/shared_ptr.hpp> #include <fstream> #include "Reverse.h" namespace libreverse { namespace trace { /* Idea taken from http://www.codeproject.com/debug/xytrace.asp * (28 Jan 2002 - Xiangyang Liu) * * I have modified this so that we don't use varargs and use constant types */ class Trace_State { public: typedef boost::shared_ptr<Trace_State> ptr_t; static Trace_State& Instance(); void set_Trace_File_Prefix ( std::string name ); void set_Trace_Level ( boost::uint32_t level ); void open_Trace_File ( void ); std::string get_ID_String ( void ); void close_Trace_File ( void ); boost::uint32_t get_Trace_Level ( void ) const; void write_Message ( boost::uint32_t level, std::string msg ); private: Trace_State(); virtual ~Trace_State(); std::string m_file_prefix; boost::uint32_t m_trace_level; std::ofstream m_log_stream; }; class Trace { public: static bool write_Trace ( boost::uint32_t level, std::string message ); }; } /* namespace trace */ } /* namespace trace */ #endif /* LIBREVERSE_TRACE_H */ --------- SOURCE ------------- #include "Trace.h" #include <boost/format.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <sstream> #ifndef WIN32 #include <unistd.h> #else #include <windows.h> #endif /* WIN32 */ namespace libreverse { namespace trace { Trace_State& Trace_State::Instance() { static Trace_State instance_obj; return instance_obj; } void Trace_State::set_Trace_File_Prefix ( std::string name ) { assert ( ! name.empty() ); // Lock the resource // Close the present file m_file_prefix = name; // Unlock the resource } void Trace_State::set_Trace_Level ( boost::uint32_t level ) { // Lock the resource // Change level m_trace_level = level; // Unlock the resource } void Trace_State::open_Trace_File ( void ) { if ( ! m_log_stream.is_open() ) { // Create file name std::stringstream name; name << boost::format("%s_%s.txt") % m_file_prefix % this->get_ID_String(); m_log_stream.open ( (name.str()).c_str() ); } } std::string Trace_State::get_ID_String ( void ) { // Create id string std::stringstream name; // Get current time boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); std::tm tm_ref = boost::posix_time::to_tm ( now ); boost::gregorian::date today = now.date(); name << boost::format ( "%s_%02d:%02d:%02d" ) % boost::gregorian::to_iso_extended_string ( today ) % tm_ref.tm_hour % tm_ref.tm_min % tm_ref.tm_sec; return name.str(); } void Trace_State::close_Trace_File ( void ) { if ( m_log_stream.is_open() ) { m_log_stream.close(); } } boost::uint32_t Trace_State::get_Trace_Level ( void ) const { boost::uint32_t level = 0; // Lock the resource // get the level level = m_trace_level; // unlock the resource // return the level return level; } void Trace_State::write_Message ( boost::uint32_t level, std::string msg ) { // Write ID m_log_stream << boost::format("%s_%d: " ) % this->get_ID_String() #ifndef WIN32 % getpid() #else % GetCurrentProcessId() #endif /* WIN32 */ << std::flush; // Write message prefix if ( level == libreverse::api::TraceLevel::TraceWarn ) { m_log_stream << "(WW) "; } else if ( level == libreverse::api::TraceLevel::TraceError ) { m_log_stream << "(EE) "; } else if ( level == libreverse::api::TraceLevel::TraceInfo ) { m_log_stream << "(II) "; } else if ( level == libreverse::api::TraceLevel::TraceDebug ) { m_log_stream << "(DEBUG) "; } else if ( level == libreverse::api::TraceLevel::TraceDetail ) { m_log_stream << "(DETAIL) "; } else if ( level == libreverse::api::TraceLevel::TraceData ) { m_log_stream << "(DATA) "; } else { // We should not be here abort(); } // Write to the file m_log_stream << msg << std::endl << std::flush; // Unlock the resource } Trace_State::Trace_State() : m_file_prefix ( "Trace" ), m_trace_level ( libreverse::api::TraceLevel::TraceNone ) {} Trace_State::~Trace_State() { this->close_Trace_File(); } #ifdef LIBREVERSE_DEBUG bool Trace::write_Trace ( boost::uint32_t level, std::string message ) { // If the level is equal to or greater than the present // level we record out message. if ( ( Trace_State::Instance().get_Trace_Level() != 0 ) && ( level <= Trace_State::Instance().get_Trace_Level() ) ) { Trace_State::Instance().write_Message ( level, message ); } return true; } #else bool Trace::write_Trace ( boost::uint32_t, std::string ) { return true; } #endif } /* namespace trace */ } /* namespace trace */

Now I am trying to be a good programmer and keep track of my pointers. So I decided that I should replace the pointer with a shared_ptr.
In regards to the validity of calling get() on an unassigned shared_ptr I thought that if a shared_ptr was declared in the header and no call is given to any constructor that the default constructor would be used. Therefore the shared_ptr would have a value of 0x0.
It would, and you shouldn't get the message. Perhaps the message comes from the copy assignment (which again, it shouldn't) - try m_instance.reset(new Trace_State()); instead. You could also simply write if (!m_instance) as shared_ptr declares operator ! just for this purpose. But I agree, in a singleton pattern you benefit from shared pointer only if the singleton lives shorter than the application and you want to make sure it's not gone while still in use. Leon

On Thu, 2007-05-17 at 16:59 +0200, Leon Mlakar wrote:
Now I am trying to be a good programmer and keep track of my pointers. So I decided that I should replace the pointer with a shared_ptr.
In regards to the validity of calling get() on an unassigned shared_ptr I thought that if a shared_ptr was declared in the header and no call is given to any constructor that the default constructor would be used. Therefore the shared_ptr would have a value of 0x0.
It would, and you shouldn't get the message. Perhaps the message comes from the copy assignment (which again, it shouldn't) - try
m_instance.reset(new Trace_State());
instead.
You could also simply write if (!m_instance) as shared_ptr declares operator ! just for this purpose.
But I agree, in a singleton pattern you benefit from shared pointer only if the singleton lives shorter than the application and you want to make sure it's not gone while still in use.
Leon
Since its suppose to live the length of the application then its alright that we make it follow the Meyers Singleton without using the boost shared_ptr. Thanks for the help. Stephen
participants (3)
-
Hughes, James
-
Leon Mlakar
-
Stephen Torri