2010-03-08 9 views
13

Por razones heredadas, necesito utilizar punteros intrusivos, ya que necesito la capacidad de convertir punteros sin procesar en punteros inteligentes.¿Hay un impulso :: weak_intrusive_pointer?

Sin embargo, noté que no hay un puntero intrusivo débil para impulsar. Encontré una charla sobre esto en la lista de hilos de refuerzo, sin embargo, nada concreto.

¿Alguien sabe de una implementación segura para hilos de un puntero intrusivo débil?

Gracias Rich

Respuesta

10

No tiene ningún sentido.

Para elaborar: weak_ptr apunta a la misma instancia de un objeto counter que shared_ptr do. Cuando el shared_ptr queda fuera del alcance, la instancia del counter permanece (con un recuento efectivo en 0), lo que permite que las instancias weak_ptr comprueben que apuntan efectivamente a un objeto liberado.

Con conteo intrusivo, el contador se integra dentro del objeto. Cuando el recuento llega a 0, el objeto generalmente se recicla o elimina ... pero el punto es que el contador ya no está disponible. La razón es que esto permite un almacenamiento más eficiente (1 porción individual) y una mayor velocidad (localidad de memoria caché).

Si necesita un conteo de referencia débil y no le importan los beneficios del conteo intrusivo, puede usar una combinación de shared_ptr y weak_ptr.

La idea es desasociar el contador de los objetos.

class Counted 
{ 
    // bla 
private: 
    boost::shared_ptr<int> mCounter; 
}; 

Ahora puede volver asas débiles:

class WeakHandle 
{ 
public: 
    explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {} 

    bool expired() const { return mCounter.expired(); } 

private: 
    boost::weak_ptr<int> mCounter; 
    Counted* mObject; 
}; 

Aquí, deassociate la vida útil del contador del tiempo de vida del objeto, de modo que sobrevivirá a la destrucción del objeto ... parcialmente. Por lo tanto, hacer el weak_ptr efectivamente posible.

Y, por supuesto, el uso de shared_ptr y weak_ptr esto es seguro para subprocesos;)

+0

Mi idea es incrustar el objeto compartido utilizado por ptr compartida y ptr débil dentro del objeto host y intrusive_weak_ptr (si existiera) lo usaría de la misma manera que lo hace weak_ptr. Todavía necesito la funcionalidad de eliminar el objeto cuando no hay más referencias. Además, necesito tomar referencias débiles. – Rich

+0

Creo que no entendiste mi punto: eso es exactamente lo que propongo. El objeto 'Contado' se cuenta 'intrusivamente', simplemente cambié el contador de un entero simple a un puntero a un número entero. En cuanto a su 'intrusive_weak_ptr' es exactamente lo que llamé' WeakHandle'. –

+0

Ah, creo que estoy contigo. Así que usaría un puntero intrusivo como siempre, sin embargo cuando se invoca intrusive_ptr_add_ref, hago referencia al int del puntero compartido como mi conteo. Cuando eso llega a cero, el objeto se libera, sin embargo, cualquier referencia débil mantiene un puntero al int. ¿Es eso correcto? – Rich

4

aplicación actual del puntero intrusivo está utilizando contador de referencia. Por lo tanto, borrar la eliminación de objetos también elimina el contador, por lo que weak_intrusive_pointer nunca sabrá que el objeto fue eliminado.

Si necesita obtener weak_ptr de this, probablemente busque boost::enable_shared_from_this<T>.

3

No me gusta ninguna de las respuestas anteriores así:

No, no sé de una aplicación, pero creo que es posible. La implementación estándar de shared_ptr tiene dos recuentos de referencia, uno para las referencias "fuerte" y otro para las referencias "débiles", y un puntero al referente. En una implementación intrusive_ptr, el recuento fuerte debe ser parte del objeto, pero el débil no puede ser. Entonces, parece que podrías crear un intrusive_ptr "débil".

Definir una débil ayudante puntero:

template<class X> 
class intrusive_ptr_weak_helper { 
    long weak_ref_count; 
    X *target_instance; 
}; 

Entonces constancia de que en el objeto al lado del contador de referencia:

struct X { 
    ... 
    intrusive_ptr_weak_helper *ref_weak_helper; 
    ... 
    long ref_count; 
    ... 
}; 

Al construir X:

ref_count = 0; 
ref_weak_helper = NULL; 

El "fuerte" puntero, intrusive_strong_ptr, es idéntico a intrusive_ptr, hasta que se produce la eliminación. Cuando el fuerte recuento ref va a cero (antes de que ocurra la eliminación):

if (ref_weak_helper != NULL) { 
    if (ref_weak_helper->weak_ref_count == 0) 
     delete ref_weak_helper; 
    else 
     ref_weak_helper->target_instance = NULL; 
} 

La "débil" versión, intrusive_weak_ptr, registra el puntero hasta el ayudante débil, la manipulación de que el contador de referencia, y el acceso al objeto de destino a través de la target_instance puntero. Cuando weak_ref_count disminuye a cero, el estado de target_instance determina si el helper se elimina o no.

Faltan muchos detalles (por ejemplo, problemas de simultaneidad) pero esta es una mezcla de shared_ptr e intrusive_ptr. Mantiene los beneficios básicos de intrusive_ptr (la optimización de la caché, la reutilización de la cuenta de ref intrusiva (fuerte) de terceros, los suplentes de puntero fuerte y débil tienen un tamaño de puntero) y agrega trabajo adicional principalmente en la ruta de referencia débil.