PDA

Visualizza la versione completa : [C++] Sostituire puntatori con shared_ptr


xxxAlex83xxx
19-01-2011, 14:03
Salve a tutti,
come posso fare in modo di sostituire i puntatori tradizionali con gli shared_ptr in un codice di questo tipo ?



#include <iostream>
#include <tr1/memory>
#include <list>

using namespace std;
using namespace std::tr1;

class Base;
class Derived;

typedef Base* spBase_t;
typedef Derived* spDerived_t;

class Base
{
public:
int type;
};

class Derived : public Base
{
public:
void print() { cout << "Hello from Derived" << endl ; }
};

int main()
{
list<spBase_t> l; //list of ponters to Base object

spBase_t d1( new Derived() ); //create derived objects
spBase_t d2( new Derived() ); //create derived objects
l.push_back(d2);
l.push_back(d2);

for (list<spBase_t>::iterator i = l.begin(); i!= l.end(); i++)
{
( (spDerived_t)(*i) )->print();
//current->print();
}
}



Se provo a sostituire banalmente le righe


typedef Base* spBase_t;
typedef Derived* spDerived_t;


con


typedef shared_ptr<Base> spBase_t;
typedef shared_ptr<Derived> spDerived_t;


il compilatore (gcc 4.2.) restituisce un errore del tipo:

/usr/include/c++/4.2.1/tr1/boost_shared_ptr.h:562: error: invalid conversion from ‘Base* const’ to ‘Derived*’

Grazie!

shodan
19-01-2011, 14:16
Usa dynamic_pointer_cast<>


for (list<spBase_t>::iterator i = l.begin(); i!= l.end(); i++)
{
spDerived_t sd = dynamic_pointer_cast<Derived>(*i);
sd->print();
}


Oppure



for (list<spBase_t>::iterator i = l.begin(); i!= l.end(); i++)
{
dynamic_pointer_cast<Derived>(*i)->print();
}

Se però il nuovo puntatore è nullo, hai un errore di accesso.

xxxAlex83xxx
19-01-2011, 14:24
Originariamente inviato da shodan
Usa dynamic_pointer_cast<>


for (list<spBase_t>::iterator i = l.begin(); i!= l.end(); i++)
{
spDerived_t sd = dynamic_pointer_cast<Derived>(*i);
sd->print();
}


Oppure



for (list<spBase_t>::iterator i = l.begin(); i!= l.end(); i++)
{
dynamic_pointer_cast<Derived>(*i)->print();
}

Se però il nuovo puntatore è nullo, hai un errore di accesso.

Innanzitutto grazie della risposta.
In realtà avevo già provato con il dynamic_pointer_cast, ma il compilatore mi restituisce

/usr/include/c++/4.2.1/tr1/boost_shared_ptr.h:613: error: cannot dynamic_cast ‘__r->std::tr1::__shared_ptr<Base, _S_atomic>::_M_ptr’ (of type ‘class Base* const’) to type ‘class Derived*’ (source type is not polymorphic)

Come puoi vedere non ho metodi polimorfici: potrei potenzialmente avere diverse classi derivate dalla medesima base ma con metodi molto diversi tra di loro.

Il motivo per cui mi serve passare dalla medesima classe base è perché, in questo modo, potrei utilizzare il container 'list', dato che mi serve mantenere una lista di oggetti appartenenti a classi diverse. All'occorrenza, iterando su questa lista e riconoscendo il tipo di oggetto, effettuo il cast opportuno e lancio i diversi metodi secondo la logica del mio programma.

Grazie

shodan
19-01-2011, 18:59
D'accordo, ma a questo punto tanto vale usare void* come tipo base ed effettuare degli static_cast appositi.
Se utilizzi una classe base, devi almeno rendere virtuale il distruttore, altrimenti non vengono richiamati i distruttori delle classi derivate se si effettua il delete del puntatore base.


class Base {
~Base() {} // può essere vuoto.
};

// oppure
class Base {
~Base()=0; // impone la derivazione forzata della classe.
};

Base::~Base() {} // se no il linker da errore.

class Derivata1 : public Base {

// dati per Derivata1

};
...
class DerivataN : public Base {

// dati per DerivataN

};

xxxAlex83xxx
19-01-2011, 19:32
Giusto, mi era sfuggito quest'ultimo punto.

Grazie mille :)

Loading