PDA

Visualizza la versione completa : [c++]sistema dataset e proprietÓ


giuseppe500
27-03-2012, 20:04
ciao,
passo direttamente alla domanda ho una serie di entitÓ come linea,quadrato,cerchio derivano tutte da CEntity.
Ogni entitÓ ha nella definizione di CEntity la possibilitÓ di aggiungere proprietÓ tipo colore , tratto,dimensioni eccc... tutte queste proprietÓ derivano da CDataset.
ora:
per aggiungere un dataset avro' il metodo AddDataset nella CEntity dove passo un istanza di CDataset cosi:



CEntity* pQuadrato= new CEntityQuad();
CDataset* pDataset = new DatasetColore();

pQudrato->AddDataset(pDataset);


ma per rimuovere un dataset particolare dala collezione interna di CDataset di CEntity come posso fare?
dovrei salvarmi tutti gli indirizzi dei dataset e poi rimuovere il dataset che ha quel particolare indirizzo ma Ŕ macchinoso e scomodo.
Il meglio sarebbe poter rimuovere i dataset o il dataset di un particolare tipo derivato, cosa usare ?
RTTI o DynamicCast o cosa?
e come?
ho letto che il dynamiccast Ŕ piuttosto lento , Ŕ vero?
oppue un sistema di flags?
bo????
grazie.

shodan
27-03-2012, 22:13
Ma addDataset dove mette il puntatore? Array? List? Vector? Altro?
Non ti basta fare una delete, mettere a nullptr il puntatore e fare un controllo sulla validita?

giuseppe500
28-03-2012, 10:14
scusa shodan, mi spiego meglio:
addDataset mette i puntatori in un vector che contiene tutti i dataset dell' entitÓ, solo che ho tanti tipi di dataset per ogni entitÓ (anche se derivano tutti d da CDataset), da qui la necessitÓ di identificare il dataset da rimuovere , io pensavo a rimuovere un dato tipo, ma Ŕ solo un idea.


grazie.

shodan
28-03-2012, 12:42
Per identificare il dataset derivato, la cosa prestazionalmente pi¨ veloce Ŕ l'accoppiata:
funzione_che_restituisce_un_flag_di_tipo + static_cast<>
segue il typeid() e infine il dynamic_cast<> (circa 10 volte pi¨ lento rispetto al primo metodo. Si parla di 4ms contro 40 comunque, non di ore).

Il problema del primo metodo, per˛, Ŕ che se hai tanti tipi derivati (non istanze, parlo di classi) , la cosa tende a diventare un po' rognosa da gestire.

Detto questo: se con "rimuovere" intendi togliere fisicamente da una locazione del vector, ricorda che il vector Ŕ lento nelle operazioni di rimozione mediane. Meglio una lista per questo.
Se intendi effettuare solo una delete sul puntatore che ti interessa, indentificare il tipo non Ŕ necessario.
Puoi chiarire questo punto?

giuseppe500
28-03-2012, 12:57
Se intendi effettuare solo una delete sul puntatore che ti interessa, indentificare il tipo non Ŕ necessario.
Puoi chiarire questo punto?

infatti , hai ragione ho girato intorno a questo problema perchŔ probabilmente non ho capito:

per fare il delete del puntatore devo sapere cosa rimuovere ma soprattutto avere l'indirizzo di cui voglio fare il delete,che sia nel vector(che adesso cambier˛ con una lista) o "fuori dalk vector".
Per esempio:
ho una classe che si occupa di svariate cose CLine , deriva da una CEntity.
CLine ha un vector



vector<CDataset> vDatasets;

i dataset saranno colore, punticliccabili ecc...
ogni dataset prende come parametro CLine nella sua proprietÓ parent.
un dataset puo' essere aggiunto o rimmosso , effettivamente se tengo traccia del suo indirizzo, ad es nella parte opengl col picking(che poi Ŕ quello che devo fare con questi dataset) sullo schermo mi faccio ritornare l'indirizzo del dataset che ho cliccato posso cancellarlo con una delete,
domanda :ma poi come rimuovere dal vector il puntatore bad pointer(penso si chiami cosi)?

Ŕ questo che intendevi?
ciao.

shodan
28-03-2012, 18:59
Se ho ben capito, devi solo trovare il puntatore che ti interessa all'interno del vector (aspetta a cambiarlo) e poi togliere quel particolare puntatore.
Questo punto Ŕ importante perchÚ la RTTI (o il sistema di flags) permette di identificare il tipo di dato, non il suo indirizzo nel vector. Stiamo parlando di un puntatore all'interno del vector, non di this: sono due cose diverse.
Con la RTTI (o il sistema di flags) puoi estrapolare tutte le istanze di un dato particolare, ma non conoscere il valore memorizzato in una locazione specifica del vector, allocata con new: quello lo devi memorizzare a parte.

A mio avviso il modo pi¨ semplice Ŕ associare a ogni istanza un indice, e usare quello per rintracciare il puntatore che ti interessa.
In quanto alla rimozione, potresti anche adottare un altro sistema.
Una volta trovato il puntatore che ti interessa, ne fai la delete e metti a nullptr il puntatore.
Quando andrai a inserire un nuovo dataset, controlli se esiste una locazione libera. Se si usi quella e setti l'indice corrispondente, se no aggiungi in coda (grosso modo Ŕ uno dei principi di funzionamento di un allocatore di memoria).
Un esempio minimale, giusto per concretizzare la cosa:


class Test {
public:
virtual int type()=0;
virtual ~Test() {}
virtual void set_pos(int p) { pos = p; }
virtual int get_pos() { return pos; }
Test* address() { return this; }
int pos;
};

class Derived : public Test {
public:
int type() { return 1; }
};

class Derived2 : public Derived {
public:
int type() { return 2; }
};

class Derived3 : public Derived2 {
public:
int type() { return 3; }
};

int main(int argc, char* argv[]) {
/* Inserimento elementi e indice */
vector<Test*> v;
v.push_back(new Derived);
v[0]->set_pos(0);
v.push_back(new Derived2);
v[1]->set_pos(1);
v.push_back(new Derived3);
v[2]->set_pos(2);

/* L'indirizzo nel vector non Ŕ quello dell'istanza */
cout << &v[0] << " --- " << v[0]->address() << endl;
cout << &v[1] << " --- " << v[1]->address() << endl;

vector<Test*>::iterator it = v.begin();
vector<Test*>::iterator ed = v.end();

/* Ricerca nel vector dell'istanza con indice x e relativo delete */
for (; it != ed; ++it) {
if (*it && (*it)->get_pos() == 1) {
delete *it;
*it = nullptr; // 0 o NULL se non C++11
}
}

/* Scansione locazioni libere. Se ne trovo una la uso */
int p=0;
for (it = v.begin(); it != ed; ++it, p++) {
if (*it == nullptr) {
*it = new Derived3;
(*it)->set_pos(p);
}
}

/* Nessuna locazione libera. */
if (p == v.size()) {
v.push_back(new Derived3);
(*v.rbegin())->set_pos(p);
}

/* Elimino tutto */
for (it = v.begin(); it != ed; ++it) {
cout << (*it)->get_pos() << endl;
delete *it;
}
}

giuseppe500
29-03-2012, 09:41
Grazie molto Shodan, ho capito, anche il discorso di andare ad utilizzare le locazioni libere , ottimo.
una sola cosa:
perchŔ non usare una mappa usando come indice il type?
non semplificherebbe il lavoro?
Penso che siano molto importanti in questo caso il numero di entity e dataset utilizzati , la mappa ha prestazioni molto buone per un numero di elementi non elevato penso, anche se non sono sicuro e chiedo.
anche perchŔ il lavoro di inserimento / rimozione sarebbe piu veloce , ma ripeto ,aspetto tua risposta.

grazie 1000.

shodan
29-03-2012, 12:46
La map Ŕ un buon compromesso tra la ricerca e la velocitÓ d'accesso all'elemento cercato, per˛ non farti ingannare dall'operator[] che possiede: l'indice della map Ŕ univoco, se non stai attento rischi memory leak.
Comunque non hai specificato la frequenza di inserimento/annullamento (quindi di ricerca) dei puntatori interessati, quindi non Ŕ possibile darti una risposta specifica, se non all'acqua di rose.

Loading