Estoy pensando en comenzar a utilizar
smart pointers de forma extensiva en todo lo que hago y estoy buscando alguna implementación que sea ligera (todo lo posible pese a usar reference counting) y no tenga dependencias externas (nada de los de
Boost). También que sea lo más cómoda de usar (lo más cercano a trabajar directamente con punteros). Alguien me recomienda alguna? Qué tal shared_ptr de STL?
Además de eso, tengo una duda. Si tengo un método que ahora tiene un parámetro de tipo Widget*, con esta nueva forma de trabajar estaría pasando un smart_pointer
&, no? Pero en este caso, como podría pasar un "puntero" de una clase derivada de Widget (polimorfismo de toda la vida, vamos)?
Una implementación sencilla seria algo así:
class Pointer
{
public:
Pointer( void *pData, int nSize = 0 )
{
this->pData = pData;
this->nSize = nSize;
nCount = 1;
}
inline void AddRef()
{
nCount++;
}
inline void Release()
{
if( nCount == 1 )
{
delete pData;
}
else
{
nCount--;
}
}
inline int GetDataSize()
{
return nSize;
}
inline void *GetData()
{
return pData;
}
inline int GetCountRefs()
{
return nCount;
}
~Pointer()
{
Release();
}
private:
void *pData;
int nSize, nCount;
};
En vez de void podrías adaptarlo a usarlo con templates, aunque este estilo de implementación es muy sencillo y tal vez se te quede corto antes de usarlo :lol: .
Cita de: "zupervaca"aunque este estilo de implementación es muy sencillo y tal vez se te quede corto antes de usarlo :lol: .
Exacto, me refería a una implementación sencilla *pero* totalmente funcional.
¿Has probado los Smart Pointers que gasta el tipo que diseño el Enginuity?
Este es el
link de la segunda parte del articulo de GameDev.net donde aparece el código de los CMMPointers y creo que también algo del sistema de gestión de memoria.
Yo creo que funcionan bastante bien, pero no és una implementación demasiado "ligera" :P
Salu2
Estoo... he mirado las MSDN y no me sale el shared_ptr. ¿Es de las STL? ¿No te estarías refiriendo al auto_ptr?
Cita de: "AK47"Estoo... he mirado las MSDN y no me sale el shared_ptr. ¿Es de las STL? ¿No te estarías refiriendo al auto_ptr?
Sí, fallo mío, shared_ptr es de Boost.
Si no encuentras nada hecho puedes echarle un ojo al libro "The Art of C++". Dedica un capitulo a crear un "Simple Garbage Collector for C++" (sin usar auto_ptr) . El libro desarrolla la clase template
class GCPtr para el manejo de los punteros.
CitarGCPtr is the heart of the garbage collector. It implements a new pointer type that keeps a reference count for objects allocated on the heap. It also provides the garbage collection functionality that recycles unused memory
Creo que colson lo que quiere es C++ con ref count porque ha visto python y se ha dado cuenta de que es un lujazo no tener que preocuparte por punteros a 0.
La razón de no usar boost es por evitar sobrecargar?
Si no quieres boost, la otra famosa es la de Loki:
http://sourceforge.net/projects/loki-lib/johnEn el libro Modern C++ Design la explican y hay un monton de información útil.
Si realmente pasas de estos tochos, igual te interesa esta:
http://yasper.sourceforge.net/
Bueno, ya te han dado montones de recursos, pero por si acaso, ésta es la implementación del smart pointer en el motor
Wild Magic de David Eberly:
Wm3SmartPointer.h // Geometric Tools, Inc.
// http://www.geometrictools.com
// Copyright (c) 1998-2006. All Rights Reserved
//
// The Wild Magic Library (WM3) source code is supplied under the terms of
// the license agreement
// http://www.geometrictools.com/License/WildMagic3License.pdf
// and may not be copied or disclosed except in accordance with the terms
// of that agreement.
#ifndef WM3SMARTPOINTER_H
#define WM3SMARTPOINTER_H
#include "Wm3FoundationLIB.h"
#include "Wm3System.h"
namespace Wm3
{
template <class T>
class Pointer
{
public:
// construction and destruction
Pointer (T* pkObject = 0);
Pointer (const Pointer& rkPointer);
~Pointer ();
// implicit conversions
operator T* () const;
T& operator* () const;
T* operator-> () const;
// assignment
Pointer& operator= (T* pkObject);
Pointer& operator= (const Pointer& rkReference);
// comparisons
bool operator== (T* pkObject) const;
bool operator!= (T* pkObject) const;
bool operator== (const Pointer& rkReference) const;
bool operator!= (const Pointer& rkReference) const;
protected:
// the shared object
T* m_pkObject;
};
#include "Wm3SmartPointer.inl"
}
#endif
Wm3SmartPointer.inl// Geometric Tools, Inc.
// http://www.geometrictools.com
// Copyright (c) 1998-2006. All Rights Reserved
//
// The Wild Magic Library (WM3) source code is supplied under the terms of
// the license agreement
// http://www.geometrictools.com/License/WildMagic3License.pdf
// and may not be copied or disclosed except in accordance with the terms
// of that agreement.
//----------------------------------------------------------------------------
template <class T>
Pointer<T>::Pointer (T* pkObject)
{
m_pkObject = pkObject;
if (m_pkObject)
{
m_pkObject->IncrementReferences();
}
}
//----------------------------------------------------------------------------
template <class T>
Pointer<T>::Pointer (const Pointer& rkPointer)
{
m_pkObject = rkPointer.m_pkObject;
if (m_pkObject)
{
m_pkObject->IncrementReferences();
}
}
//----------------------------------------------------------------------------
template <class T>
Pointer<T>::~Pointer ()
{
if (m_pkObject)
{
m_pkObject->DecrementReferences();
}
}
//----------------------------------------------------------------------------
template <class T>
Pointer<T>::operator T* () const
{
return m_pkObject;
}
//----------------------------------------------------------------------------
template <class T>
T& Pointer<T>::operator* () const
{
return *m_pkObject;
}
//----------------------------------------------------------------------------
template <class T>
T* Pointer<T>::operator-> () const
{
return m_pkObject;
}
//----------------------------------------------------------------------------
template <class T>
Pointer<T>& Pointer<T>::operator= (T* pkObject)
{
if (m_pkObject != pkObject)
{
if (pkObject)
{
pkObject->IncrementReferences();
}
if (m_pkObject)
{
m_pkObject->DecrementReferences();
}
m_pkObject = pkObject;
}
return *this;
}
//----------------------------------------------------------------------------
template <class T>
Pointer<T>& Pointer<T>::operator= (const Pointer& rkPointer)
{
if (m_pkObject != rkPointer.m_pkObject)
{
if (rkPointer.m_pkObject)
{
rkPointer.m_pkObject->IncrementReferences();
}
if (m_pkObject)
{
m_pkObject->DecrementReferences();
}
m_pkObject = rkPointer.m_pkObject;
}
return *this;
}
//----------------------------------------------------------------------------
template <class T>
bool Pointer<T>::operator== (T* pkObject) const
{
return (m_pkObject == pkObject);
}
//----------------------------------------------------------------------------
template <class T>
bool Pointer<T>::operator!= (T* pkObject) const
{
return (m_pkObject != pkObject);
}
//----------------------------------------------------------------------------
template <class T>
bool Pointer<T>::operator== (const Pointer& rkPointer) const
{
return (m_pkObject == rkPointer.m_pkObject);
}
//----------------------------------------------------------------------------
template <class T>
bool Pointer<T>::operator!= (const Pointer& rkPointer) const
{
return (m_pkObject != rkPointer.m_pkObject);
}
//-----------------------------------------
Esto de los auto_pointers que funcion tiene exactamente, para que sirven?
Seria recomdable usarlos? o solo hay que usarlos en ciertos casos?
Cita de: "josette"Esto de los auto_pointers que funcion tiene exactamente, para que sirven?
Seria recomdable usarlos? o solo hay que usarlos en ciertos casos?
No me hagas mucho caso porque yo el tema este "ni papa". El auto_ptr es un puntero que se elimina solo y creo que tambien, puede cambiar el tipo de objeto al que apunta en tiempo de ejecución ( corregidme si me equivoco ).
Básicamente simplifica la gestión de memoria:
void jarl()
{
Bullet *pBullet = new Bullet;
}
// Memory leak!
Su version auto_ptr-ril:
void jarl()
{
std::auto_ptr<Bullet> pBullet;
pBullet.reset(new Bullet);
}
// pBullet es liberado automáticamente
Obviamente esto es un ejemplo sencillo. Puedes usar auto_ptr como variable miembro de una clase, por ejemplo. Así, al destruirse un objeto de esa clase, el auto_ptr dará buena cuenta de su puntero (vamos, que le hará un delete :P)
Ok, lo pillo. Pero no siempre que se use un puntero ha de usarse el auto_ptr, porque no siempre interesa que se borre.
Si bien lo comprendo, el auto_ptr es para gestionar recursos de forma que cuando un objeto se va a cargar un recurso si ya esta cargado pues se incrementa el contador y si no lo esta pues se carga. Y conforme los objetos que usan el recurso se van eliminando cuando se vaya a eliminar el ultimo pues se libera el recurso.
editado:
Tb es verdad que a veces hay objetos que interesa que se creen admitiendo parametros que se saben en tiempo de ejecucion y por tanto se ha de declarar como punteros, aunque teoricamente deberían ser Objetos. Por ejemplo:
class Cgame
{
Cplayer m_Player;
}
si Player se tubiera que crear con parametros entonces
class Cgame
{
Cplayer* m_player;
init(...,...,...){ m_player = new Cplayer(...);
}
y luego hay que destruirlo;
Pues se usa auto_ptr y asi el player se destruye el solo cuando se destruya Cgame.
class Cgame
{
auto_ptr m_Ptr_player;
init(...,...,...){ Ptr_player.reset(new Cplayer(...));
}
aunque donde hay un buen programador hay un buen destrutor!!! ;)