/////////////////////////////////////////////////////////////////////////////
// Name: object.h
-// Purpose: interface of wxObjectRefData
+// Purpose: interface of wxRefCounter
// Author: wxWidgets team
// RCS-ID: $Id$
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
-/**
- @class wxObjectRefData
+/** @class wxObjectRefData
+
+ This class is just a typedef to wxRefCounter and is used by wxObject.
- This class is used to store reference-counted data.
+ Derive classes from this to store your own data in wxObject-derived
+ classes. When retrieving information from a wxObject's reference data,
+ you will need to cast to your own derived class.
- Derive classes from this to store your own data. When retrieving information
- from a wxObject's reference data, you will need to cast to your own derived class.
+ Below is an example illustrating how to store reference counted
+ data in a class derived from wxObject including copy-on-write
+ semantics.
- @b Example:
+ @section objectrefdata_example Example
@code
// include file
+ // ------------
- class MyCar: public wxObject
+ class MyCar : public wxObject
{
public:
MyCar() { }
// implementation
+ // --------------
- class MyCarRefData: public wxObjectRefData
+ // the reference data class is typically a private class only visible in the
+ // implementation source file of the refcounted class.
+ class MyCarRefData : public wxObjectRefData
{
public:
MyCarRefData()
MyCarRefData( const MyCarRefData& data )
: wxObjectRefData()
{
+ // copy refcounted data; this is usually a time- and memory-consuming operation
+ // and is only done when two (or more) MyCar instances need to unshare a
+ // common instance of MyCarRefData
m_price = data.m_price;
}
return m_price == data.m_price;
}
+ private:
+ // in real world, reference counting is usually used only when
+ // the wxObjectRefData-derived class holds data very memory-consuming;
+ // in this example the various MyCar instances may share a MyCarRefData
+ // instance which however only takes 4 bytes for this integer!
int m_price;
};
#define M_CARDATA ((MyCarRefData *)m_refData)
-
IMPLEMENT_DYNAMIC_CLASS(MyCar,wxObject)
MyCar::MyCar( int price )
{
+ // here we init the MyCar internal data:
m_refData = new MyCarRefData();
M_CARDATA->m_price = price;
}
bool MyCar::operator == ( const MyCar& car ) const
{
- if (m_refData == car.m_refData) return true;
-
- if (!m_refData || !car.m_refData) return false;
-
+ if (m_refData == car.m_refData)
+ return true;
+ if (!m_refData || !car.m_refData)
+ return false;
+
+ // here we use the MyCarRefData::operator==() function.
+ // Note however that this comparison may be very slow if the
+ // reference data contains a lot of data to be compared.
return ( *(MyCarRefData*)m_refData == *(MyCarRefData*)car.m_refData );
}
void MyCar::SetPrice( int price )
{
+ // since this function modifies one of the MyCar internal property,
+ // we need to be sure that the other MyCar instances which share the
+ // same MyCarRefData instance are not affected by this call.
+ // I.e. it's very important to call UnShare() in all setters of
+ // refcounted classes!
UnShare();
M_CARDATA->m_price = price;
{
wxCHECK_MSG( IsOk(), -1, "invalid car" );
- return (M_CARDATA->m_price);
+ return M_CARDATA->m_price;
}
@endcode
@see wxObject, wxObjectDataPtr<T>, @ref overview_refcount
*/
-class wxObjectRefData
+typedef wxRefCounter wxObjectRefData;
+
+
+/**
+ @class wxRefCounter
+
+ This class is used to manage reference-counting providing a simple
+ interface and a counter. wxRefCounter can be easily used together
+ with wxObjectDataPtr<T> to ensure that no calls to wxRefCounter::DecRef()
+ are missed - thus avoiding memory leaks.
+
+ wxObjectRefData is a typedef to wxRefCounter and is used as the
+ built-in reference counted storage for wxObject-derived classes.
+
+ @library{wxbase}
+ @category{rtti}
+
+ @see wxObject, wxObjectRefData, wxObjectDataPtr<T>, @ref overview_refcount
+*/
+class wxRefCounter
{
protected:
/**
Destructor.
- It's declared @c protected so that wxObjectRefData instances
+ It's declared @c protected so that wxRefCounter instances
will never be destroyed directly but only as result of a DecRef() call.
*/
- ~wxObjectRefData();
+ virtual ~wxRefCounter();
public:
/**
Default constructor. Initialises the internal reference count to 1.
*/
- wxObjectRefData();
+ wxRefCounter();
/**
Decrements the reference count associated with this shared data and, if
- it reaches zero, destroys this instance of wxObjectRefData releasing its
+ it reaches zero, destroys this instance of wxRefCounter releasing its
memory.
Please note that after calling this function, the caller should
wxObject can be used to implement @ref overview_refcount "reference counted"
objects, such as wxPen, wxBitmap and others
(see @ref overview_refcount_list "this list").
+ See wxRefCounter and @ref overview_refcount for more info about
+ reference counting.
@library{wxbase}
@category{rtti}
- @see wxClassInfo, @ref overview_debugging, wxObjectRefData
+ @see wxClassInfo, @ref overview_debugging, @ref overview_refcount,
+ wxObjectDataRef, wxObjectDataPtr<T>
*/
class wxObject
{
public:
+ /**
+ Default ctor; initializes to @NULL the internal reference data.
+ */
wxObject();
/**
Copy ctor.
+
+ Sets the internal wxObject::m_refData pointer to point to the same
+ instance of the wxObjectRefData-derived class pointed by @c other and
+ increments the refcount of wxObject::m_refData.
*/
wxObject(const wxObject& other);
-
/**
Destructor.
*/
virtual ~wxObject();
- /**
- A virtual function that may be redefined by derived classes to allow dumping of
- memory states.
-
- This function is only defined in debug build and exists only if @c __WXDEBUG__
- is defined.
-
- @param stream
- Stream on which to output dump information.
-
- @remarks Currently wxWidgets does not define Dump() for derived classes,
- but programmers may wish to use it for their own applications.
- Be sure to call the Dump member of the class's base class to allow all
- information to be dumped.
- The implementation of this function in wxObject just writes
- the class name of the object.
- */
- void Dump(ostream& stream);
-
/**
This virtual function is redefined for every class that requires run-time
type information, when using the ::DECLARE_CLASS macro (or similar).
void UnRef();
/**
- Ensure that this object's data is not shared with any other object.
-
- If we have no data, it is created using CreateRefData() below,
- if we have shared data, it is copied using CloneRefData(),
- otherwise nothing is done.
+ This is the same of AllocExclusive() but this method is public.
*/
void UnShare();
void* operator new(size_t size, const wxString& filename = NULL, int lineNum = 0);
protected:
+ /**
+ Ensure that this object's data is not shared with any other object.
+
+ If we have no data, it is created using CreateRefData();
+ if we have shared data (i.e. data with a reference count greater than 1),
+ it is copied using CloneRefData(); otherwise nothing is done (the data
+ is already present and is not shared by other object instances).
+
+ If you use this function you should make sure that you override the
+ CreateRefData() and CloneRefData() functions in your class otherwise
+ an assertion will fail at runtime.
+ */
+ void AllocExclusive();
+
+ /**
+ Creates a new instance of the wxObjectRefData-derived class specific to
+ this object and returns it.
+
+ This is usually implemented as a one-line call:
+ @code
+ wxObjectRefData *MyObject::CreateRefData() const
+ {
+ return new MyObjectRefData;
+ }
+ @endcode
+ */
+ virtual wxObjectRefData *CreateRefData() const;
+
+ /**
+ Creates a new instance of the wxObjectRefData-derived class specific to
+ this object and initializes it copying @a data.
+
+ This is usually implemented as a one-line call:
+ @code
+ wxObjectRefData *MyObject::CloneRefData(const wxObjectRefData *data) const
+ {
+ // rely on the MyObjectRefData copy ctor:
+ return new MyObjectRefData(*(MyObjectRefData *)data);
+ }
+ @endcode
+ */
+ virtual wxObjectRefData *CloneRefData(const wxObjectRefData *data) const;
/**
Pointer to an object which is the object's reference-counted data.
@see Ref(), UnRef(), SetRefData(), GetRefData(), wxObjectRefData
*/
- wxObjectRefData* m_refData;
+ wxObjectRefData* m_refData;
};
/**
Finds the wxClassInfo object for a class with the given @a name.
*/
- static wxClassInfo* FindClass(wxChar* name);
+ static wxClassInfo* FindClass(const wxString& className);
/**
Returns the name of the first base class (@NULL if none).
*/
- wxChar* GetBaseClassName1() const;
+ const wxChar* GetBaseClassName1() const;
/**
Returns the name of the second base class (@NULL if none).
*/
- wxChar* GetBaseClassName2() const;
+ const wxChar* GetBaseClassName2() const;
/**
Returns the string form of the class name.
*/
- wxChar* GetClassName() const;
+ const wxChar* GetClassName() const;
/**
Returns the size of the class.
*/
int GetSize() const;
- /**
- Initializes pointers in the wxClassInfo objects for fast execution of IsKindOf().
- Called in base wxWidgets library initialization.
- */
- static void InitializeClasses();
-
/**
Returns @true if this class info can create objects of the associated class.
*/
/**
Returns @true if this class is a kind of (inherits from) the given class.
*/
- bool IsKindOf(wxClassInfo* info);
+ bool IsKindOf(const wxClassInfo* info) const;
};
/**
- This is helper template class primarily written to avoid memory leaks because of
- missing calls to wxObjectRefData::DecRef().
+ This is an helper template class primarily written to avoid memory leaks because
+ of missing calls to wxRefCounter::DecRef() and wxObjectRefData::DecRef().
Despite the name this template can actually be used as a smart pointer for any
class implementing the reference counting interface which only consists of the two
methods @b T::IncRef() and @b T::DecRef().
The difference to wxSharedPtr<T> is that wxObjectDataPtr<T> relies on the reference
- counting to be in the class pointed to where instead wxSharedPtr<T> implements the
+ counting to be in the class pointed to, where instead wxSharedPtr<T> implements the
reference counting itself.
+ Below is an example illustrating how to implement reference counted
+ data using wxRefCounter and wxObjectDataPtr<T> with copy-on-write
+ semantics.
- @b Example:
+ @section objectdataptr_example Example
@code
- class MyCarRefData: public wxObjectRefData
+ class MyCarRefData: public wxRefCounter
{
public:
- MyCarRefData() { m_price = 0; }
-
- MyCarRefData( const MyCarRefData& data )
- : wxObjectRefData()
- {
- m_price = data.m_price;
- }
+ MyCarRefData( int price = 0 ) : m_price(price) { }
+ MyCarRefData( const MyCarRefData& data ) : m_price(data.m_price) { }
void SetPrice( int price ) { m_price = price; }
- int GetPrice() { return m_price; }
+ int GetPrice() const { return m_price; }
protected:
int m_price;
class MyCar
{
public:
- MyCar( int price ) : m_data( new MyCarRefData )
+ // initializes this MyCar assigning to the
+ // internal data pointer a new instance of MyCarRefData
+ MyCar( int price = 0 ) : m_data( new MyCarRefData(price) )
{
- m_data->SetPrice( price );
}
MyCar& operator =( const MyCar& tocopy )
{
+ // shallow copy: this is just a fast copy of pointers; the real
+ // memory-consuming data which typically is stored inside
+ // MyCarRefData is not copied here!
m_data = tocopy.m_data;
return *this;
}
bool operator == ( const MyCar& other ) const
{
- if (m_data.get() == other.m_data.get()) return true;
- return (m_data->GetPrice() == other.m_data->GetPrice());
+ if (m_data.get() == other.m_data.get())
+ return true; // this instance and the 'other' one share the
+ // same MyCarRefData data...
+
+ return (m_data.GetPrice() == other.m_data.GetPrice());
}
void SetPrice( int price )
{
- UnShare();
- m_data->SetPrice( price );
+ // make sure changes to this class do not affect other instances
+ // currently sharing our same refcounted data:
+ UnShare();
+
+ m_data->SetPrice( price );
}
int GetPrice() const
@see wxObject, wxObjectRefData, @ref overview_refcount, wxSharedPtr<T>,
wxScopedPtr<T>, wxWeakRef<T>
*/
+template <class T>
class wxObjectDataPtr<T>
{
public:
// Global functions/macros
// ============================================================================
-/** @ingroup group_funcmacro_rtti */
+/** @addtogroup group_funcmacro_rtti */
//@{
/**
//@}
-/** @ingroup group_funcmacro_debug */
+/** @addtogroup group_funcmacro_debug */
//@{
/**