Ejemplo para usar el rpp compartido?


Hola hice una pregunta hoy sobre Cómo insertar diferentes tipos de objetos en la misma matriz vectorial y mi código en esa pregunta fue

 gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
 .....
 ......
 virtual void Run()
   {   //A virtual function
   }
};
class ANDgate :public gate 
  {.....
   .......
   void Run()
   {
    //AND version of Run
   }  

};
 class ORgate :public gate 
  {.....
   .......
   void Run()
   {
    //OR version of Run
   }  

};      
//Running the simulator using overloading concept
 for(...;...;..)
 {
  G[i]->Run() ;  //will run perfectly the right Run for the right Gate type
 } 

Y quería usar vectores así que alguien escribió que debería hacer eso:

std::vector<gate*> G;
G.push_back(new ANDgate); 
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
  G[i]->Run();
}

Pero luego él y muchos otros sugirieron que usaría mejor Los contenedores de puntero Boost
o shared_ptr. He pasado las últimas 3 horas leyendo sobre este tema, pero la documentación me parece bastante avanzada . ****Puede cualquiera me da un pequeño ejemplo de código del uso de shared_ptr y por qué sugirieron usar shared_ptr. También hay otros tipos, como ptr_vector, ptr_list y ptr_deque** **

Edit1: También he leído un ejemplo de código que incluía:

typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
  std::vector<FooPtr>         foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
  foo_vector.push_back( foo_ptr );
...........
}

Y no entiendo la sintaxis!

Author: Community, 2010-08-13

7 answers

Usando un vector de shared_ptr elimina la posibilidad de fuga de memoria porque se olvidó de caminar el vector y llamar delete en cada elemento. Vamos a recorrer una versión ligeramente modificada del ejemplo línea por línea.

typedef boost::shared_ptr<gate> gate_ptr;

Cree un alias para el tipo de puntero compartido. Esto evita la fealdad en el lenguaje C++ que resulta de escribir std::vector<boost::shared_ptr<gate> > y olvidar el espacio entre el cierre mayor que los signos.

    std::vector<gate_ptr> vec;

Crea un vector vacío de boost::shared_ptr<gate> objeto.

    gate_ptr ptr(new ANDgate);

Asigna una nueva instancia ANDgate y guárdala en una shared_ptr. La razón para hacer esto por separado es para evitar un problema que puede ocurrir si una operación se lanza. Esto no es posible en este ejemplo. El Boost shared_ptr "Best Practices" explica por qué es un best practice asignar un objeto independiente en lugar de un temporal.

    vec.push_back(ptr);

Esto crea un nuevo puntero compartido en el vector y copia ptr en él. Referencia contar en las tripas de shared_ptr asegura que el objeto asignado dentro de ptr se transfiere de forma segura al vector.

Lo que no se explica es que el destructor de shared_ptr<gate> asegura que la memoria asignada se borre. Aquí es donde se evita la pérdida de memoria. El destructor para std::vector<T> asegura que el destructor para T es llamado para cada elemento almacenado en el vector. Sin embargo, el destructor para un puntero (e. g., gate*) no borra la memoria que tenía asignado. Eso es lo que estás tratando de evitar usando shared_ptr o ptr_vector.

 111
Author: D.Shawley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-13 13:36:27

Voy a añadir que una de las cosas importantes acerca de shared_ptr es solo siempre construirlos con la siguiente sintaxis:

shared_ptr<Type>(new Type(...));

De esta manera, el puntero "real" a Type es anónimo para su ámbito, y se mantiene solo por el puntero compartido. Por lo tanto, será imposible para usted utilizar accidentalmente este puntero "real". En otras palabras, nunca hagas esto:

Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around!  Don't use it!

Aunque esto funcionará, ahora tiene un puntero Type* (t_ptr) en su función que vive fuera el puntero compartido. Es peligroso usar t_ptr en cualquier lugar, porque nunca se sabe cuándo el puntero compartido que lo contiene puede destruirlo, y se segmentará.

Lo mismo ocurre con los punteros devueltos por otras clases. Si una clase que no escribiste te entrega un puntero, generalmente no es seguro simplemente ponerlo en un shared_ptr. No a menos que esté seguro de que la clase ya no está usando ese objeto. Porque si lo pones en un shared_ptr, y cae fuera del alcance, el objeto obtendrá liberado cuando la clase aún lo necesite.

 40
Author: Ken Simon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-04 23:19:57

Aprender a usar punteros inteligentes es, en mi opinión, uno de los pasos más importantes para convertirse en un programador competente de C++. Como usted sabe cada vez que usted nuevo un objeto en algún momento que desea eliminarlo.

Un problema que surge es que, con excepciones, puede ser muy difícil asegurarse de que un objeto se libere siempre una sola vez en todas las rutas de ejecución posibles.

Esta es la razón de RAII: http://en.wikipedia.org/wiki/RAII

Hacer una clase auxiliar con el propósito de asegurarse de que un objeto siempre se elimina una vez en todas las rutas de ejecución.

Ejemplo de una clase como esta es: std:: auto_ptr

Pero a veces te gusta compartir objetos con otros. Solo se debe eliminar cuando nadie lo use más.

Con el fin de ayudar con que se han desarrollado estrategias de recuento de referencia, pero todavía necesita recordar addref y release ref manualmente. En esencia, este es el mismo problema que new / delete.

Es por eso que boost se ha desarrollado boost:: shared_ptr, es puntero inteligente de conteo de referencia para que pueda compartir objetos y no perder memoria involuntariamente.

Con la adición de C++ tr1, esto también se agrega al estándar de c++, pero se llama std::tr1::shared_ptr.

Recomiendo usar el puntero compartido estándar si es posible. ptr_list, ptr_dequeue y so son contenedores IIRC especializados para tipos de puntero. Los ignoro por ahora.

Así que podemos empezar con tu ejemplo:

std::vector<gate*> G; 
G.push_back(new ANDgate);  
G.push_back(new ORgate); 
for(unsigned i=0;i<G.size();++i) 
{ 
  G[i]->Run(); 
} 

El problema aquí es ahora que cada vez que G sale del alcance filtramos los 2 objetos agregados a G. Reescribámoslo para usar std:: tr1:: shared_ptr

// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to 
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;    
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G; 
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));  
G.push_back(gate_ptr (new ORgate)); 
for(unsigned i=0;i<G.size();++i) 
{ 
   G[i]->Run(); 
} 

Cuando G se sale del alcance, la memoria se recupera automáticamente.

Como un ejercicio con el que plagé a los recién llegados en mi equipo es pedirles que escriban su propia clase de puntero inteligente. Luego, una vez que haya terminado, deseche la clase inmediatamente y nunca vuelva a usarla. Esperemos que haya adquirido conocimientos cruciales sobre cómo funciona un puntero inteligente bajo el capó. No hay magia de verdad.

 19
Author: Just another metaprogrammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-13 13:12:17

La documentación de boost proporciona un buen ejemplo de inicio: shared_ptr ejemplo (en realidad se trata de un vector de punteros inteligentes) o shared_ptr doc La siguiente respuesta de Johannes Schaub explica los punteros inteligentes boost bastante bien: se explican los punteros inteligentes

La idea detrás (en tan pocas palabras como sea posible) ptr_vector es que maneja la desasignación de memoria detrás de los punteros almacenados para usted: digamos que tiene un vector de punteros como en su ejemplo. Al salir de la aplicación o salir del ámbito en el que se define el vector tendrás que limpiar después de ti mismo(has asignado dinámicamente ANDgate y ORgate), pero simplemente borrar el vector no lo hará porque el vector está almacenando los punteros y no los objetos reales(no destruirá sino lo que contiene).

 // if you just do
 G.clear() // will clear the vector but you'll be left with 2 memory leaks
 ...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
  delete (*it);
}

Boost::ptr_vector se encargará de lo anterior, lo que significa que desasignará la memoria detrás de los punteros que almacena.

 2
Author: celavek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:00

A través de Boost puedes hacerlo >

std::vector<boost::any> vecobj;
    boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));    
    boost::shared_ptr<int> sharedint1(new int(10));
    vecobj.push_back(sharedString1);
    vecobj.push_back(sharedint1);

> para insertar diferentes tipos de objeto en su contenedor vectorial. mientras que para acceder tienes que usar any_cast, que funciona como dynamic_cast, espera que funcione para tu necesidad.

 2
Author: user1808932,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-29 13:42:28
#include <memory>
#include <iostream>

class SharedMemory {
    public: 
        SharedMemory(int* x):_capture(x){}
        int* get() { return (_capture.get()); }
    protected:
        std::shared_ptr<int> _capture;
};

int main(int , char**){
    SharedMemory *_obj1= new SharedMemory(new int(10));
    SharedMemory *_obj2 = new SharedMemory(*_obj1);
    std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
    << std::endl;
    delete _obj2;

    std::cout << " _obj1: " << *_obj1->get() << std::endl;
    delete _obj1;
    std::cout << " done " << std::endl;
}

Este es un ejemplo de shared_ptr en acción. _obj2 fue eliminado, pero el puntero sigue siendo válido. la salida es, ./prueba _obj1: 10 _obj2: 10 _obj2: 10 hecho

 1
Author: Syed Raihan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-10 14:49:07

La mejor manera de agregar diferentes objetos en el mismo contenedor es usar make_shared, vector y range based loop y tendrá un código agradable, limpio y "legible".

typedef std::shared_ptr<gate> Ptr   
vector<Ptr> myConatiner; 
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);

for (auto& element : myConatiner)
    element->run();
 0
Author: Hooman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-31 16:45:16