2013-04-15 18 views
5

Ho un puntatore ad un vettore:come creare un vettore di puntatori a un vettore

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
vector<double>* new_mv_pt = new vector<double> (3); 
new_mv_pt = &mv;  

cout << (*new_mv_pt)[1] << endl;  

Come posso fare un altro vettore che memorizzerà questo puntatore ad un vettore? Stavo cercando questo ...

vector<double*> vop = new vector<double> (3); 

vop.push_back(*new_mv_pt); 

cout << (*vop)[1] << endl; 

, ma non ha funzionato. È quello che sto tentando anche possibile ?:

+2

In primo luogo, ottenere la risposta. In secondo luogo, renditi conto che questa è un'idea orribile perché stai eliminando la capacità del vettore di gestire la memoria per te, che è (almeno) metà del punto di utilizzo in primo luogo. –

+0

Sto solo cercando di capire perché ha un puntatore a un vettore in primo luogo. Non ha senso concettuale farlo in questo modo, specialmente se si trova nella stessa funzione/classe. –

risposta

3

Sì, ma è necessario fare questo:

vector<vector<double>*> vop; 

Perché siete alla ricerca di un elenco di puntatori vettoriali.

quello che avete qui:

vector<double *> vop 

è solo un vettore di double puntatori.

Inoltre si vuole proprio questo:

vop.push_back(new_mv_pt); // <- No asterisk (you don't want to de-reference it) 
+0

Come dovrei fare per eliminare entrambi i puntatori per evitare perdite nella memoria? Provo a cancellare new_mv_pt e ottengo qualche tipo di errore di asserzione in fase di esecuzione. Qual è il problema? –

+0

Cosa intendi per entrambi i puntatori? vuoi dire 'new_mv_pt' e quello nel vettore? –

+0

Beh, quando provo a eliminare new_mv_pt senza essere nel vettore dei puntatori, non funzionerà e si presenta con una sorta di errore di asserzione in fase di esecuzione. Alla fine vorrei sapere come cancellare tutto in modo sicuro. –

2

Hai una perdita di memoria qui:

vector<double>* new_mv_pt = new vector<double> (3); 
new_mv_pt = &mv; 

si sta creando un vector<double> sul mucchio, la memorizzazione è l'indirizzo in new_mv_pt, e poi sovrascrivendo l'indirizzo con l'indirizzo mv. Il vector<double> esiste ancora nell'heap, ma hai perso definitivamente il suo indirizzo (e quindi non hai modo di farlo con delete o fare qualsiasi altra cosa con esso).

Questo codice:

vector<double*> vop = new vector<double> (3); 
vop.push_back(*new_mv_pt); 
cout << (*vop)[1] << endl; 

non funziona perché vop è un vettore di double* s, e si sta tentando di inserire un vector<double> in esso. Vedere Ben's answer per l'approccio corretto.

7

Whoa, rallenti!

Stai facendo cose piuttosto folli con la tua memoria, quindi iniziamo dall'inizio.

Si dispone di un singolo vettore che contiene 3 elementi. Vuoi fare riferimento a quel vettore usando un puntatore. Vediamo come che sembra:

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
// No no no no! You don't have to `new` a pointer that 
// you're going to assign to something else! 
// This is called a memory leak, and it means you've just wasted (!!!) 
// C++ memory! Don't do it 
// vector<double>* new_mv_pt = new vector<double> (3); 
// Instead, do this: 
vector<double>* ptr_to_mv = &mv; // No leak, immediately points to a vector<double> mv; 

che si prende cura del primo bit. Ora, approfondiamoci un po '. Vuoi memorizzare un vettore di riferimenti a vettori. Va bene, sembra giusto. Ci sono alcuni modi per farlo.Torniamo all'esempio di mv e altre cose:

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 
vector<double>* ptr_to_mv = &mv; 
// So far so good. Now, based on your question, you want 
// to have a list of these to point to. So: 
vector<vector<double>*> vop; 
vop.push_back(ptr_to_mv); // All clean. 

A questo punto nel codice, è necessario accedere vop con .at() o operator[] per arrivare a un vector<double>*, allora si dereferenziarlo con * o l'uso -> a lavorare su di esso direttamente:

std::vector<double>* ptr_to_vector = vop[0]; // Got my pointer 
std::cout << ptr_to_vector->at(0) << std::endl; // Prints '233' 

questo stampa 233, perché tutto questo è che si fa riferimento a mv. In un commento in un'altra risposta, hai detto che quando elimini questi puntatori, ottieni un'asserzione. Questo dovrebbe succedere, perché stai cancellando le cose due volte!

Ricorda mv, che hai dichiarato molto tempo fa? Beh, non lo hai reso un vettore dinamico. Non lo hai new e non è un puntatore. Quindi, quando la funzione termina, si cancellerà automaticamente - chiamerà il suo distruttore e die nello stack. Se si guarda ptr_to_vector o ptr_to_mv, fanno tutti riferimento a mv, che si pulisce da solo.

Se si chiama delete su di esso, si sta cercando di chiamare cancellare il mv (che è quello che si sta puntando a) e il gioco è doppio cancellazione!

Così, quando si ha un puntatore a mv, non eliminarlo. È una variabile basata sullo stack. Si pulirà da solo.

Ancora seguito? Grande, cerchiamo di entrare in un po 'di più:

Ora, se c'è un ragione è necessario new su un vettore, non si assegna la precedenza con un vecchio puntatore (come vi ho detto prima, lascerai la memoria). Si effettua una nuova puntatore completamente nuovo:

// Our vector of double vector pointers 
vector<vector<double>*> vop; 

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 

// References a stack variable: don't delete 
vector<double>* ptr_to_mv = &mv; 
vop.push_back(ptr_to_mv); 

// Makes a fresh copy of mv. You must delete this 
// manually 
vector<double>* fresh_ptr = new vector<double>(mv); 
(*fresh_ptr)[0] = 1337; 
// changes only data in fresh_ptr, not `mv` 
vop.push_back(fresh_ptr); 

/* Blah blah blah, work */ 
// Functions about to exit, gotta clean up! 
delete fresh_ptr; 
//delete ptr_to_mv; // NO. 
//delete vop[0]; // NO! 
//delete vop[1]; // ... Already deleted from fresh_ptr 
// ... This is going to get tedious if we don't have a fresh_ptr 
// for every vector we need! 

Quanto sopra mostra il problema: abbiamo 2 puntatori, sia all'interno vop, dove uno ha bisogno di essere ripulito chiamando cancellare, e un altro che non lo fa perché è solo un riferimento a mv, che pulisce automaticamente! Fare il ciclo sul vettore e cancellare tutto farà sì che quella brutta affermazione accada. Come lo affrontiamo e otteniamo ancora la pulizia di cui abbiamo bisogno?

Soluzione rapida e sporca 1 è a solo delete vop[1]/fresh_ptr e deve essere fatto con esso. La soluzione migliore è che, ogni volta che si aggiunge una risorsa a new, lo si avvolge in questa meravigliosa cosa denominata std::unique_ptr. Il codice sarà simile a questa:

// Our vector of double vector pointers. Non-owning 
vector<vector<double>*> vop; 

vector<double> mv; 
mv.push_back(233); 
mv.push_back(234); 
mv.push_back(654); 

// References a stack variable: don't delete 
vector<double>* ptr_to_mv = &mv; 
vop.push_back(ptr_to_mv); 

// Makes a fresh copy of mv 
// puts it inside a std::unique_ptr, 
// which, like a stack-based vector, 
// can clean itself up 
std::unique_ptr<vector<double>> fresh_ptr(new vector<double>(mv)); 
vop.push_back(fresh_ptr.get()); 

/* Blah blah blah, work */ 
// Functions about to exit, gotta clean up! 
//delete fresh_ptr; // Not necessary 
//delete ptr_to_mv; // Nope.jpg 

E ci si va, rimuovere tutto quel codice commentato-out e all'improvviso, la tua roba è pulito come un fischio!

Naturalmente, ora, l'ultima domanda che ho per voi è: Che diavolo stai facendo che richiede tutti questi puntatori a puntatori a riferimenti di puntatori di vettori?

+0

Questo è stato estremamente utile. Mi hai insegnato molto. Grazie mille. –

+0

Questa è una risposta incredibilmente dettagliata a una domanda molto semplice. Lei è un professionista! +1 –

Problemi correlati