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?
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. –
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. –