Remove obsolete classes:

Legacy workarounds for Visual Studio non thread-safe initialization
of function local objects with static storage duration are removed:

* Remove LeakChecked
* Remove StaticObject
* Remove SharedSingleton
This commit is contained in:
Vinnie Falco
2015-02-11 10:39:08 -08:00
committed by Tom Ritchford
parent 11c472d701
commit df89999891
24 changed files with 39 additions and 676 deletions

View File

@@ -52,9 +52,7 @@
#include <beast/utility/Debug.h>
#include <beast/utility/Error.h>
#include <beast/utility/Journal.h>
#include <beast/utility/LeakChecked.h>
#include <beast/utility/PropertyStream.h>
#include <beast/utility/StaticObject.h>
#include <beast/module/core/system/StandardIncludes.h>
@@ -144,7 +142,6 @@ class FileOutputStream;
#include <beast/module/core/streams/FileInputSource.h>
#include <beast/module/core/streams/OutputStream.h>
#include <beast/module/core/files/FileOutputStream.h>
#include <beast/module/core/memory/SharedSingleton.h>
#include <beast/module/core/streams/MemoryOutputStream.h>
#include <beast/module/core/system/SystemStats.h>

View File

@@ -41,7 +41,7 @@ namespace beast {
It can also guess how far it's got using a wildly inaccurate algorithm.
*/
class DirectoryIterator : LeakChecked <DirectoryIterator>
class DirectoryIterator
{
public:
//==============================================================================
@@ -119,7 +119,7 @@ public:
private:
//==============================================================================
class NativeIterator : LeakChecked <NativeIterator>
class NativeIterator
{
public:
NativeIterator (const File& directory, const String& wildCard);

View File

@@ -22,29 +22,16 @@
//==============================================================================
#include <beast/unit_test/suite.h>
#include <beast/utility/static_initializer.h>
#include <algorithm>
#include <memory>
namespace beast {
// We need to make a shared singleton or else there are
// issues with the leak detector and order of detruction.
//
class NonexistentHolder
File const& File::nonexistent()
{
public:
static NonexistentHolder* getInstance()
{
return SharedSingleton <NonexistentHolder>::getInstance();
}
File file;
};
File const& File::nonexistent ()
{
return NonexistentHolder::getInstance ()->file;
static beast::static_initializer<File> instance;
return *instance;
}
//------------------------------------------------------------------------------

View File

@@ -35,7 +35,6 @@ namespace beast
*/
class FileInputStream
: public InputStream
, LeakChecked <FileInputStream>
{
public:
//==============================================================================

View File

@@ -35,7 +35,6 @@ namespace beast
*/
class FileOutputStream
: public OutputStream
, LeakChecked <FileOutputStream>
{
public:
//==============================================================================

View File

@@ -25,7 +25,6 @@
#define BEAST_MODULE_CORE_MEMORY_MEMORYBLOCK_H_INCLUDED
#include <beast/HeapBlock.h>
#include <beast/utility/LeakChecked.h>
#include <beast/strings/String.h>
namespace beast {
@@ -35,7 +34,7 @@ namespace beast {
A class to hold a resizable block of raw data.
*/
class MemoryBlock : LeakChecked <MemoryBlock>
class MemoryBlock
{
public:
//==============================================================================

View File

@@ -1,205 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MODULE_CORE_MEMORY_SHAREDSINGLETON_H_INCLUDED
#define BEAST_MODULE_CORE_MEMORY_SHAREDSINGLETON_H_INCLUDED
#include <beast/threads/SpinLock.h>
#include <beast/smart_ptr/SharedPtr.h>
#include <beast/module/core/time/AtExitHook.h>
#include <atomic>
namespace beast
{
/** Thread-safe singleton which comes into existence on first use. Use this
instead of creating objects with static storage duration. These singletons
are automatically reference counted, so if you hold a pointer to it in every
object that depends on it, the order of destruction of objects is assured
to be correct.
Object Requirements:
DefaultConstructible
TriviallyDestructible (when lifetime == neverDestroyed)
Destructible
@class SharedSingleton
@ingroup beast_core
*/
/** @{ */
class SingletonLifetime
{
public:
// It would be nice if we didn't have to qualify the enumeration but
// Argument Dependent Lookup is inapplicable here because:
//
// "Base classes dependent on a template parameter aren't part of lookup."
// - ville
//
/** Construction options for SharedSingleton
@ingroup beast_core
*/
enum Lifetime
{
/** Created on first use, destroyed when the last reference is removed.
*/
createOnDemand,
/** The singleton is created on first use and persists until program exit.
*/
persistAfterCreation,
/** The singleton is created when needed and never destroyed.
This is useful for applications which do not have a clean exit.
*/
neverDestroyed
};
};
//------------------------------------------------------------------------------
/** Wraps object to produce a reference counted singleton. */
template <class Object>
class SharedSingleton
: public Object
, private SharedObject
{
public:
typedef SharedPtr <SharedSingleton <Object> > Ptr;
static Ptr get (SingletonLifetime::Lifetime lifetime
= SingletonLifetime::persistAfterCreation)
{
StaticData& staticData (getStaticData ());
SharedSingleton* instance = staticData.instance;
if (instance == nullptr)
{
std::lock_guard <LockType> lock (staticData.mutex);
instance = staticData.instance;
if (instance == nullptr)
{
bassert (lifetime == SingletonLifetime::createOnDemand || ! staticData.destructorCalled);
staticData.instance = &staticData.object;
new (staticData.instance) SharedSingleton (lifetime);
std::atomic_thread_fence (std::memory_order_seq_cst);
instance = staticData.instance;
}
}
return instance;
}
// DEPRECATED LEGACY FUNCTION NAME
static Ptr getInstance (SingletonLifetime::Lifetime lifetime
= SingletonLifetime::persistAfterCreation)
{
return get (lifetime);
}
private:
explicit SharedSingleton (SingletonLifetime::Lifetime lifetime)
: m_lifetime (lifetime)
, m_exitHook (this)
{
if (m_lifetime == SingletonLifetime::persistAfterCreation ||
m_lifetime == SingletonLifetime::neverDestroyed)
this->incReferenceCount ();
}
~SharedSingleton ()
{
}
void onExit ()
{
if (m_lifetime == SingletonLifetime::persistAfterCreation)
this->decReferenceCount ();
}
void destroy () const
{
bool callDestructor;
// Handle the condition where one thread is releasing the last
// reference just as another thread is trying to acquire it.
//
{
StaticData& staticData (getStaticData ());
std::lock_guard <LockType> lock (staticData.mutex);
if (this->getReferenceCount() != 0)
{
callDestructor = false;
}
else
{
callDestructor = true;
staticData.instance = nullptr;
staticData.destructorCalled = true;
}
}
if (callDestructor)
{
bassert (m_lifetime != SingletonLifetime::neverDestroyed);
this->~SharedSingleton();
}
}
typedef SpinLock LockType;
// This structure gets zero-filled at static initialization time.
// No constructors are called.
//
class StaticData
{
public:
LockType mutex;
SharedSingleton* instance;
SharedSingleton object;
bool destructorCalled;
StaticData() = delete;
StaticData(StaticData const&) = delete;
StaticData& operator= (StaticData const&) = delete;
~StaticData() = delete;
};
static StaticData& getStaticData ()
{
static std::uint8_t storage [sizeof (StaticData)];
return *(reinterpret_cast <StaticData*> (&storage [0]));
}
friend class SharedPtr <SharedSingleton>;
friend class AtExitMemberHook <SharedSingleton>;
SingletonLifetime::Lifetime m_lifetime;
AtExitMemberHook <SharedSingleton> m_exitHook;
};
//------------------------------------------------------------------------------
} // beast
#endif

View File

@@ -399,7 +399,6 @@ bool File::setAsCurrentWorkingDirectory() const
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl
: LeakChecked <DirectoryIterator::NativeIterator::Pimpl>
{
public:
Pimpl (const File& directory, const String& wildCard)

View File

@@ -35,7 +35,6 @@ namespace beast
*/
class FileInputSource
: public InputSource
, LeakChecked <FileInputSource>
{
public:
//==============================================================================

View File

@@ -36,7 +36,7 @@ namespace beast
@see FileInputSource
*/
class InputSource : LeakChecked <InputSource>
class InputSource
{
public:
//==============================================================================

View File

@@ -38,7 +38,6 @@ class MemoryBlock;
@see OutputStream, FileInputStream
*/
class InputStream
: LeakChecked <InputStream>
{
public:
/** Destructor. */

View File

@@ -43,7 +43,6 @@ namespace beast
*/
class MemoryOutputStream
: public OutputStream
, LeakChecked <MemoryOutputStream>
{
public:
//==============================================================================

View File

@@ -17,12 +17,13 @@
*/
//==============================================================================
#include <beast/utility/static_initializer.h>
namespace beast
{
class DeadlineTimer::Manager
: public LeakChecked <Manager>
, protected Thread
: protected Thread
{
private:
typedef CriticalSection LockType;
@@ -42,6 +43,14 @@ public:
bassert (m_items.empty ());
}
static
Manager&
instance()
{
static beast::static_initializer<Manager> m;
return *m;
}
// Okay to call on an active timer.
// However, an extra notification may still happen due to concurrency.
//
@@ -210,19 +219,18 @@ private:
DeadlineTimer::DeadlineTimer (Listener* listener)
: m_listener (listener)
, m_manager (SharedSingleton <Manager>::getInstance ())
, m_isActive (false)
{
}
DeadlineTimer::~DeadlineTimer ()
{
m_manager->deactivate (*this);
Manager::instance().deactivate (*this);
}
void DeadlineTimer::cancel ()
{
m_manager->deactivate (*this);
Manager::instance().deactivate (*this);
}
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
@@ -232,7 +240,7 @@ void DeadlineTimer::setExpiration (double secondsUntilDeadline)
RelativeTime const when (
RelativeTime::fromStartup() + secondsUntilDeadline);
m_manager->activate (*this, 0, when);
Manager::instance().activate (*this, 0, when);
}
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
@@ -242,7 +250,7 @@ void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
RelativeTime const when (
RelativeTime::fromStartup() + secondsUntilDeadline);
m_manager->activate (*this, secondsUntilDeadline, when);
Manager::instance().activate (*this, secondsUntilDeadline, when);
}
} // beast

View File

@@ -20,8 +20,6 @@
#ifndef BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
#define BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
#include <beast/module/core/memory/SharedSingleton.h>
namespace beast {
/** Provides periodic or one time notifications at a specified time interval.
@@ -108,7 +106,6 @@ private:
class Manager;
Listener* const m_listener;
SharedPtr <SharedSingleton <Manager> > m_manager;
bool m_isActive;
RelativeTime m_notificationTime;
double m_secondsRecurring; // non zero if recurring

View File

@@ -17,8 +17,9 @@
*/
//==============================================================================
namespace beast
{
#include <beast/utility/static_initializer.h>
namespace beast {
// Manages the list of hooks, and calls
// whoever is in the list at exit time.
@@ -33,7 +34,9 @@ public:
static inline Manager& get ()
{
return StaticObject <Manager>::get();
static beast::static_initializer<
Manager> instance;
return *instance;
}
void insert (Item& item)
@@ -73,10 +76,6 @@ private:
AtExitHook* const hook (item.hook ());
hook->onExit ();
}
// Now do the leak checking
//
LeakCheckedBase::checkForLeaks ();
}
struct StaticDestructor

View File

@@ -61,7 +61,6 @@
#define BEAST_MODULE_SQDB_API_SESSION_H_INCLUDED
#include <beast/smart_ptr/SharedPtr.h>
#include <beast/module/core/memory/SharedSingleton.h>
namespace beast {
namespace sqdb {
@@ -137,8 +136,6 @@ private:
Error hard_exec(std::string const& query);
private:
class Sqlite3;
SharedPtr <SharedSingleton <Sqlite3> > m_instance;
bool m_bInTransaction;
sqlite3* m_connection;
String m_fileName;

View File

@@ -62,26 +62,27 @@
namespace beast {
namespace sqdb {
class session::Sqlite3
class Sqlite3Instance
{
public:
Sqlite3()
Sqlite3Instance()
{
assert (sqlite3_threadsafe() != 0);
sqlite3_initialize();
}
~Sqlite3()
~Sqlite3Instance()
{
sqlite3_shutdown();
}
};
Sqlite3Instance sqlite3_instance;
//------------------------------------------------------------------------------
session::session()
: prepare (this)
, m_instance (SharedSingleton <Sqlite3>::getInstance ())
, m_bInTransaction (false)
, m_connection (nullptr)
{
@@ -89,7 +90,6 @@ session::session()
session::session(const session& deferredClone)
: prepare (this)
, m_instance (SharedSingleton <Sqlite3>::getInstance ())
, m_bInTransaction (false)
, m_connection (nullptr)
, m_fileName (deferredClone.m_fileName)

View File

@@ -24,7 +24,6 @@
#ifndef BEAST_THREADS_THREAD_H_INCLUDED
#define BEAST_THREADS_THREAD_H_INCLUDED
#include <beast/utility/LeakChecked.h>
#include <beast/threads/RecursiveMutex.h>
#include <beast/threads/WaitableEvent.h>
@@ -43,7 +42,7 @@ namespace beast {
@see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow,
MessageManagerLock
*/
class Thread : LeakChecked <Thread>
class Thread
{
public:
//==============================================================================

View File

@@ -38,7 +38,6 @@ namespace beast {
method.
*/
class WaitableEvent
//, LeakChecked <WaitableEvent> // VFALCO TODO Move LeakChecked to beast/
{
public:
//==============================================================================

View File

@@ -1,181 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UTILITY_LEAKCHECKED_H_INCLUDED
#define BEAST_UTILITY_LEAKCHECKED_H_INCLUDED
#include <beast/Config.h>
#include <beast/intrusive/LockFreeStack.h>
#include <beast/utility/StaticObject.h>
#include <atomic>
namespace beast {
namespace detail {
class LeakCheckedBase
{
public:
static void checkForLeaks ();
protected:
class LeakCounterBase : public LockFreeStack <LeakCounterBase>::Node
{
public:
LeakCounterBase ();
virtual ~LeakCounterBase ()
{
}
inline int increment ()
{
return ++m_count;
}
inline int decrement ()
{
return --m_count;
}
virtual char const* getClassName () const = 0;
private:
void checkForLeaks ();
virtual void checkPureVirtual () const = 0;
class Singleton;
friend class LeakCheckedBase;
std::atomic <int> m_count;
};
static void reportDanglingPointer (char const* objectName);
};
//------------------------------------------------------------------------------
/** Detects leaks at program exit.
To use this, derive your class from this template using CRTP (curiously
recurring template pattern).
*/
template <class Object>
class LeakChecked : private LeakCheckedBase
{
protected:
LeakChecked () noexcept
{
getCounter ().increment ();
}
LeakChecked (LeakChecked const&) noexcept
{
getCounter ().increment ();
}
~LeakChecked ()
{
if (getCounter ().decrement () < 0)
{
reportDanglingPointer (getLeakCheckedName ());
}
}
private:
// Singleton that maintains the count of this object
//
class LeakCounter : public LeakCounterBase
{
public:
LeakCounter () noexcept
{
}
char const* getClassName () const
{
return getLeakCheckedName ();
}
void checkPureVirtual () const { }
};
private:
/* Due to a bug in Visual Studio 10 and earlier, the string returned by
typeid().name() will appear to leak on exit. Therefore, we should
only call this function when there's an actual leak, or else there
will be spurious leak notices at exit.
*/
static const char* getLeakCheckedName ()
{
return typeid (Object).name ();
}
// Retrieve the singleton for this object
//
static LeakCounter& getCounter () noexcept
{
return StaticObject <LeakCounter>::get();
}
};
}
//------------------------------------------------------------------------------
namespace detail
{
namespace disabled
{
class LeakCheckedBase
{
public:
static void checkForLeaks ()
{
}
};
template <class Object>
class LeakChecked : public LeakCheckedBase
{
public:
};
}
}
//------------------------------------------------------------------------------
// Lift the appropriate implementation into our namespace
//
#if BEAST_CHECK_MEMORY_LEAKS
using detail::LeakChecked;
using detail::LeakCheckedBase;
#else
using detail::disabled::LeakChecked;
using detail::disabled::LeakCheckedBase;
#endif
}
#endif

View File

@@ -1,124 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UTILITY_STATICOBJECT_H_INCLUDED
#define BEAST_UTILITY_STATICOBJECT_H_INCLUDED
#include <atomic>
#include <chrono>
#include <thread>
namespace beast {
// Spec: N2914=09-0104
//
// [3.6.2] Initialization of non-local objects
//
// Objects with static storage duration (3.7.1) or thread storage
// duration (3.7.2) shall be zero-initialized (8.5) before any
// other initialization takes place.
//
/** Wrapper to produce an object with static storage duration.
The object is constructed in a thread-safe fashion when the get function
is first called. Note that the destructor for Object is never called. To
invoke the destructor, use the AtExitHook facility (with caution).
The Tag parameter allows multiple instances of the same Object type, by
using different tags.
Object must meet these requirements:
DefaultConstructible
@see AtExitHook
*/
template <class Object, typename Tag = void>
class StaticObject
{
public:
static Object& get ()
{
StaticData& staticData (StaticData::get());
if (staticData.state.load () != initialized)
{
if (staticData.state.exchange (initializing) == uninitialized)
{
// Initialize the object.
new (&staticData.object) Object;
staticData.state = initialized;
}
else
{
std::size_t n = 0;
while (staticData.state.load () != initialized)
{
++n;
std::this_thread::yield ();
if (n > 10)
{
std::chrono::milliseconds duration (1);
if (n > 100)
duration *= 10;
std::this_thread::sleep_for (duration);
}
}
}
}
assert (staticData.state.load () == initialized);
return staticData.object;
}
private:
static int const uninitialized = 0;
static int const initializing = 1;
static int const initialized = 2;
// This structure gets zero-filled at static initialization time.
// No constructors are called.
//
class StaticData
{
public:
std::atomic <int> state;
Object object;
static StaticData& get ()
{
static std::uint8_t storage [sizeof (StaticData)];
return *(reinterpret_cast <StaticData*> (&storage [0]));
}
StaticData() = delete;
StaticData(StaticData const&) = delete;
StaticData& operator= (StaticData const&) = delete;
~StaticData() = delete;
};
};
}
#endif

View File

@@ -25,7 +25,6 @@
#include <beast/utility/impl/Debug.cpp>
#include <beast/utility/impl/Journal.cpp>
#include <beast/utility/impl/LeakChecked.cpp>
#include <beast/utility/impl/PropertyStream.cpp>
#include <beast/utility/tests/bassert.test.cpp>

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <beast/utility/Journal.h>
#include <beast/module/core/memory/SharedSingleton.h>
#include <beast/utility/static_initializer.h>
namespace beast {
@@ -60,8 +60,8 @@ public:
Journal::Sink& Journal::getNullSink ()
{
return *SharedSingleton <NullJournalSink>::get (
SingletonLifetime::neverDestroyed);
static beast::static_initializer<NullJournalSink> sink;
return *sink;
}
//------------------------------------------------------------------------------

View File

@@ -1,102 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/utility/LeakChecked.h>
namespace beast {
namespace detail
{
class LeakCheckedBase::LeakCounterBase::Singleton
{
public:
void push_back (LeakCounterBase* counter)
{
m_list.push_front (counter);
}
void checkForLeaks ()
{
for (;;)
{
LeakCounterBase* const counter = m_list.pop_front ();
if (!counter)
break;
counter->checkForLeaks ();
}
}
static Singleton& getInstance ()
{
static Singleton instance;
return instance;
}
private:
friend class LeakCheckedBase;
LockFreeStack <LeakCounterBase> m_list;
};
//------------------------------------------------------------------------------
LeakCheckedBase::LeakCounterBase::LeakCounterBase ()
: m_count (0)
{
Singleton::getInstance ().push_back (this);
}
void LeakCheckedBase::LeakCounterBase::checkForLeaks ()
{
// If there's a runtime error from this line, it means there's
// an order of destruction problem between different translation units!
//
this->checkPureVirtual ();
int const count = m_count.load ();
if (count > 0)
{
outputDebugString ("Leaked objects: " + std::to_string (count) +
" instances of " + getClassName ());
}
}
//------------------------------------------------------------------------------
void LeakCheckedBase::reportDanglingPointer (char const* objectName)
{
outputDebugString (std::string ("Dangling pointer deletion: ") + objectName);
bassertfalse;
}
//------------------------------------------------------------------------------
void LeakCheckedBase::checkForLeaks ()
{
LeakCounterBase::Singleton::getInstance ().checkForLeaks ();
}
}
}