2011-04-15 17 views
8

Sin experiencia con shared_ptr<> Me pregunto si el siguiente es un caso de uso apropiado y si es una buena idea devolver shared_ptr<> al usuario.Uso apropiado de shared_ptr?

Tengo una estructura similar a un gráfico con múltiples conexiones entre los nodos. Durante la travesía del gráfico, a cada nodo se le asigna un valor (calculado a partir de nodos conectados) y deseo que el usuario pueda acceder al valor fácilmente. Todo esto se ve (muy simplificada) como este:

class Pool; 
class Node { 
    public: 
     typedef std::tr1::shared_ptr<Node> Ptr; 
     ... 
     void compute_dependencies() { 
      ... 
      // calls Pool to get a new Node instance 
      dependencies_.push_back(Pool::create_node(...)); 
      ... 
     } 

     // evaluate the current node 
     void evaluate() { /* use dependencies_ */ };   
     double value() const { if(evaluated) return value_; }; 

    private: 
     std::vector<Node::Ptr> dependencies_;   // vector<Node*> better? 
     dbl value_; 
} 

// Pool creates and owns all nodes 
class Pool { 
    public: 
     static const Node::Ptr create_node(...);   // create a new node 
     void traverse_and_evaluate();  

    private: 
     std::vector<Node::Ptr> allnodes; // appropriately sorted to ensure 
              // dependencies are evaluated 
     ... 
} 

y el usuario llama:

Pool pool(); 
Node::Ptr node1 = Pool::create_node(...); 
Node::Ptr node2 = Pool::create_node(...); 
.... 
pool.traverse_and_evaluate(); 
// ready to read out the now populated values 
cout << node1->value() << " " << node2->value() << ... 

Esto tiene la ventaja de que el usuario obtiene directamente el acceso a los nodos importantes para él (dependencias son a menudo poco interesante). Pero no estoy 100% seguro de si esta es una buena idea.

Gracias por su ayuda!

Editar: No hay dependencias circulares.

+0

Puede encontrar esta pregunta, y las respuestas, algo relevantes: http://stackoverflow.com/questions/5629592/resource-leak-during-object-creation-c/ – Anton

Respuesta

10

shared_ptr es principalmente útil para los tiempos cuando un objeto no tiene un dueño bien definido (o tal vez necesite sobrevivir a su dueño), entonces no hay un lugar obvio para destruirlo. El shared_ptr esencialmente se convierte en el propietario, y el objeto se destruye cuando el último shared_ptr queda fuera del alcance.

Cuando usted tiene un dueño claro, al igual que la clase Pool, y no hay necesidad de que los objetos Node sobrevivir al Pool poseer, a continuación, en realidad no hay mucha necesidad de un shared_ptr. Puedes destruir los objetos en el destructor del propietario.

+0

Gracias, eso lo hace bastante un poco más claro. Entonces, ¿qué estás diciendo es que 'create_node()' debería devolver un puntero sin formato que esté almacenado dentro de un 'vector allnodes'? Una copia no es una opción, ya que el 'Nodo' no se evalúa en la creación. – bbtrb

+3

@bbtrb: devolver un 'Node *' está bien, pero sugeriría usar un 'std :: vector ' en su lugar (sin pérdida). Si realmente no puede copiar 'Node' (si es una clase base), puede usar' boost :: ptr_vector '. –

+0

@bbtrb: sí, devolver un puntero sin procesar sería suficiente para esto. –

3

Me gusta proporcionar acceso a otros a través de weak_ptr, puede construir un nodo weak_ptr <> directamente desde un nodo shared_ptr <>.

El usuario generalmente recuperaría un weak_ptr del Pool y luego construiría un shared_ptr < Node> from the weak_ptr < Node> .lock().

Esto transmite al usuario que no tiene derechos de propiedad, y debe tener cuidado de no mantener el bloqueo más largo de lo necesario - o al menos lo hace para mí :)

Cuestiones relacionadas