2012-02-14 6 views
5

Lectura de Alexandrescu y wikipipidia Veo que la punta y el contador de referencia se almacenan en el montón. Entonces, ¿se menciona que el recuento de referencias es ineficiente ya que el contador debe asignarse en el montón? ¿Por qué no está almacenado en la pila?¿Por qué las implementaciones de puntero inteligente de C++ mantienen el contador de referencia en el montón junto con el puntero?

+0

¿Puedes mostrar un ejemplo de lo que estás describiendo? –

+0

¿De qué otro modo lo harías? –

+0

Tanto el "contador de referencia" como el "montón" son meros detalles de implementación.La verdadera cuestión es que la semántica de propiedad compartida solo se puede implementar con asignación dinámica. –

Respuesta

9

Porque lo perdería tan pronto como la instancia actual del puntero inteligente salga del alcance.

Un puntero inteligente se utiliza para simular objetos de almacenamiento automático que se asignaron dinámicamente. Los punteros inteligentes en sí mismos se administran automáticamente. Entonces, cuando uno es destruido, todo lo que almacena en el almacenamiento automático también se destruye. Pero no quiere perder el contador de referencia. Entonces lo almacena en almacenamiento dinámico.

3

No se puede almacenar en la pila porque una copia del objeto también daría lugar a una copia del recuento, lo que anularía su propósito.

1

Como otros han señalado, la pila no es un lugar apropiado para mantener la cuenta de referencia debido a que el objeto puede sobrevivir al marco de pila actual (en cuyo caso el contador de referencias se iría!)

Vale la pena señalando que algunas de las ineficiencias asociadas con poner el recuento de referencias en el montón se pueden superar al almacenarlas "juntas" con el objeto mismo. En el impulso, esto se puede lograr utilizando boost::make_shared (para shared_ptr) o boost::intrusive_ptr.

1

Existen diferentes tipos de punteros inteligentes, diseñados para diferentes propósitos. El puntero del que está hablando es un puntero inteligente compartido (std::shared_ptr), que ayuda a compartir la propiedad de objetos desde varios lugares. Todas las copias de shared_ptr incrementan y disminuyen la misma variable de contador, que se coloca en el montón, ya que debe estar disponible para todas las copias del shared_ptr incluso después de que la primera copia muera.

Por lo tanto, shared_ptr mantiene internamente dos punteros: al objeto y al contador. Pseudocódigo:

class SharedPointer<T> { 
public: 
// ... 
private: 
    T* obj; 
    int* counter; 
} 

Por cierto, cuando se crea objeto con std::make_shared, la implementación puede optimizar la asignación mediante la asignación de memoria suficiente para mantener tanto el contador y el objeto y luego construirlas de lado a lado.

Este truco en su extremo nos da un patrón de recuento de referencia intrusivo: el objeto mantiene internamente su contador y proporciona las funciones AddRef y Release para incrementarlo y disminuirlo. Puede usar puntero inteligente intrusivo, p. boost::intrusive_ptr, que utiliza esta maquinaria y, por lo tanto, no necesita asignar otro contador por separado. Esto es más rápido en términos de asignaciones, pero requiere inyectar el contador a la definición de clase controlada.

Además, cuando no es necesario compartir la propiedad de objeto y sólo necesita controlar su tiempo de vida (de manera que se consigue cuando se devuelve la función destructed), se puede utilizar el con ámbito puntero inteligente: std::unique_ptr o boost::scoped_ptr. No necesita el contador por completo, ya que solo existe una copia del unique_ptr.

Cuestiones relacionadas