2010-03-11 20 views
14

Ho un vettore dichiarato come variabile globale che devo essere in grado di riutilizzare. Ad esempio, sto leggendo più file di dati, analizzando i dati per creare oggetti che sono poi memorizzati in un vettore.Riutilizzare un vettore in C++

vector<Object> objVector(100); 

void main() 
{ 
while(THERE_ARE_MORE_FILES_TO_READ) 
{ 
    // Pseudocode 
    ReadFile(); 
    ParseFileIntoVector(); 
    ProcessObjectsInVector(); 
    /* Here I want to 'reset' the vector to 100 empty objects again */ 

} 

}

Posso ripristinare il vettore di essere "objVector vettore (100)" Da quando è stato inizialmente allocato sullo stack? Se faccio "objVector.clear()", rimuove tutti i 100 oggetti e vorrei avere un vettore con una dimensione di 0. Ho bisogno che sia una dimensione di 100 all'inizio di ogni ciclo.

+0

È necessario conservare gli oggetti o ripristinarli allo stato predefinito? – Macke

+1

Nell'esempio, objVector è assegnato staticamente. Non è allocato nello stack. – Alan

+3

Il tipo di restituzione della funzione principale non è corretto. In C e C++ main deve sempre restituire int (ma se in realtà non si restituisce nulla, C++ e C99 restituiranno automaticamente 0 per te). – Tronic

risposta

4
vector<Object> objVector(100); 

int main() 
{ 
while(THERE_ARE_MORE_FILES_TO_READ) 
{ 
    // Pseudocode 
    ReadFile(); 
    ParseFileIntoVector(); 
    ProcessObjectsInVector(); 
    /* Here I want to 'reset' the vector to 100 empty objects again */ 
    objVector.clear(); 
    objVector.resize(100); 

} 
} 
+0

Questo l'ha fatto. Grazie! – Blade3

+2

Bene, continuo a pensare che swap() sia il modo migliore per fare questo tipo di lavoro. Vedere l'articolo 17 di STL effettivi: utilizzare "il trucco swap" per ridurre la capacità in eccesso. fare un chiaro e poi ridimensionare è in realtà più lento - ha operazioni di allocazione di memoria extra rispetto allo scambio() –

+2

Rifinire la capacità in eccesso è più spesso non desiderato (è per questo che stdlib non lo fa neanche). C'è un calo di prestazioni causato da frequenti allocazioni. Il vantaggio prestazionale cercato riutilizzando il vettore sarebbe stato completamente perso. – Tronic

2

chiamata ridimensionare all'inizio o alla fine del ciclo: http://www.cplusplus.com/reference/stl/vector/resize/

che dovrebbe fare quello che vuoi. Tuttavia, consiglierei di utilizzare invece le funzioni push e pop. È più efficiente in termini di spazio ed è il modo in cui è stato progettato il vettore. Il vettore si espanderà e si restringerà se necessario quando si spingono (aggiungi) e si estrae (rimuovi) elementi da esso. In questo modo non devi preoccuparti delle dimensioni o dei contenuti del vettore. Diventa semplicemente una coda di elaborazione.

1

Il seguente codice dovrebbe fare il trucco.

vector<Object> temp(100); 
objVector.swap(temp); 
+0

Ciò non aiuta molto dal momento in cui scarti un vettore diverso, ma lo scarti ancora. –

+0

@Let_Me_Be: questo scarta ciò che si aveva già, sostituendolo con 100 oggetti predefiniti - ciò che l'OP chiedeva. – UncleBens

+0

@Let_Me_Be: In realtà non capisco il tuo commento. Potresti per favore chiarire un po '? –

6
objVector.clear(); 
objVector.resize(100); 

Tuttavia, questo è probabilmente non è raccomandato l'uso di vettore. Sei sicuro che non dovresti usare push_back con un vettore inizialmente vuoto? Come puoi essere sicuro che ogni file contenga esattamente 100 oggetti, né più né meno, come appare dalla tua domanda?

Probabilmente il vettore non ha bisogno di essere globale. Meglio passare le cose in giro. Quando vedi una serie di funzioni chiamate senza parametri, è piuttosto difficile se non impossibile seguire quello che sta succedendo (perché tutti gli altri tranne te - e includendo te quando ritorni a questo codice dopo alcuni mesi) avranno non ho idea di cosa queste funzioni utilizzino per l'input e qual è l'output).

0

Chiama objVector.clear() per rimuovere i punti di dati precedenti e quindi objVector.resize(100) per ridimensionarlo alla dimensione appropriata.

Si noti, tuttavia, che questo assegnerà 1 istanza di Object utilizzando il costruttore predefinito e quindi 100 copie di Object utilizzando il costruttore di copie, che potrebbe essere o meno ciò che si desidera effettivamente. Facoltativamente, se Object è un tipo di puntatore, è possibile utilizzare objVector.resize(100, NULL) per evitare allocazioni potenzialmente indesiderate.

+0

Nessuna assegnazione indesiderata avverrà se 'Object' è un tipo di puntatore, passare' NULL' a 'ridimensiona' è completamente ridondante, poiché lo stesso potrebbe accadere senza di esso. –

+0

Inoltre, l'affermazione relativa al costruttore di copie è errata. Il costruttore predefinito verrebbe chiamato ogni volta, cioè 100 volte. –

+0

@Konrad ti sbagli sul secondo punto. L'impostazione predefinita può essere chiamata 100 volte nel caso in cui la classe abbia solo costruttori impliciti, ma un'app di prova rapida mostrerà che il costruttore di copie è effettivamente chiamato se implementato. Tuttavia, mi sbagliavo: il costruttore di default è chiamato una volta, e il costruttore di copia è chiamato 100 volte, non 99. – Dathan

11

Ho un vettore dichiarato come variabile globale che devo essere in grado di riutilizzare.

Perché? Non è chiaro dal tuo codice perché la variabile deve essere globale. Perché non puoi dichiararlo all'interno del ciclo? Quindi non è necessario ripristinarlo, questo sarà fatto automaticamente in ogni ciclo.

Per accedere alla variabile dagli altri metodi, passarla come parametro (per riferimento, in modo da poterlo modificare). Avere una variabile globale è raramente una buona soluzione.

Un'altra cosa: main must mai hanno tipo di ritorno void, questo non è valido C++ e molti compilatori lo rifiuterà.

0

Poiché si utilizza il costruttore predefinito per "Oggetto", penso che si dovrebbe poter fare affidamento sulla capacità del vettore anziché sulle sue dimensioni. Quindi, quando chiami clear(), è probabile che tu non stia cambiando la capacità impostata dal tuo costruttore di vettori (puoi tenere almeno 100 elementi, sono già allocati). Leggi la capacità, la riserva e le dimensioni e il modo in cui ciascuna di esse differisce (riserva è la chiamata che farai per richiedere cambiamenti di capacità, la sto solo indicando nel caso tu ne abbia bisogno).

Ad ogni modo, se è necessario ripristinare gli oggetti allo stato predefinito, anziché affidarsi alla possibilità di eseguire un ripristino a livello vettoriale degli oggetti, è possibile anche effettuare una chiamata sul proprio oggetto denominato "reset" "per impostarli su quello stato e chiamarli prima di rielaborarli utilizzando quegli stessi oggetti. Per quanto riguarda le prestazioni, non lo vedo come diverso, e in termini di codice sembra una soluzione pulita.

1

Contrariamente agli altri posti, il modo più efficace per fare questo è probabilmente questo:

objVector.resize(0); 
objVector.resize(100); 

clear() libera la memoria del vettore su alcuni implementazioni (la sua postcondizione solo richiesto è quella dimensione() = 0). ridimensiona (0) mantiene la capacità.

Il trucco di swap richiama anche un'allocazione di memoria non necessaria. Il vettore temporaneo che si scambia assegnerà un nuovo blocco di memoria e, dopo lo scambio, verrà rilasciato anche il vecchio blocco di memoria. Le prestazioni dovrebbero essere migliori senza allocazioni di memoria.

+0

In realtà, ho cercato. Mentre in C++ 03 sia '.clear()' che '.resize (0)' non potevano causare una riallocazione (perché ciò avrebbe invalidato '.begin()', che C++ 03 non consentiva), C++ 0x sembra consentire sia '.clear()' che '.resize (0)' per riallocare (dato che ora possono invalidare '.begin()'). Ovviamente, una riallocazione non implica un cambiamento della capacità, quindi non si può sostenere che "poiché la capacità non cambierà, non si verificherà alcuna riallocazione", penso. –

+0

La modifica silenziosa che ha reso '.resize (0)' e '.clear()' potrebbe essere riallineata è questa: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects. html # 414 (notate che entrambi devono ancora riallocare alla stessa quantità o maggiore quantità di memoria immagazzinata nella capacità, quindi sarebbe piuttosto inutile per loro riallocare. Ma in teoria, potrebbero leggerlo correttamente). –

+0

Heh, questo si è rivelato più complicato di quanto pensassi. Grazie per i commenti. – AshleysBrain

2

Perché stai tentando di ripristinare una variabile globale? Basta assegnare un nuovo vettore ogni volta attraverso il ciclo e passare il vettore nelle funzioni per riferimento.

void ParseFileIntoVector(vector<Object> &vector); 
void ProcessObjectsInVector(const vector<Object> &vector); 

int main() 
{ 
while(THERE_ARE_MORE_FILES_TO_READ) 
{ 
    // Pseudocode 
    vector<Object> objVector(100); 
    ReadFile(); 
    ParseFileIntoVector(objVector); 
    ProcessObjectsInVector(objVector); 
} 
} 
0
Posso resettare il vettore per essere "vector objVector (100)" poiché inizialmente era allocato nello stack?
  1. I vettori C++ non sono allocati nello stack. Almeno non direttamente. Uno dei parametri per il vettore (e altri modelli STL) è l'allocatore. È possibile utilizzare gli allocatori di pool, gli allocatori di heap ecc.

    Il std::vector<T> è infatti un puntatore ben impacchettato per array con informazioni aggiuntive (come dimensioni e capacità). Altrimenti la dimensione del vettore doveva essere conosciuta in anticipo (che non è richiesta).

  2. Infatti nell'esempio sopra lo std::vector<T> non è nello stack ma nella sezione dati del programma (o come viene chiamato su piattaforme non ELF).

Quindi la domanda è se è necessario:

  • Un vettore di dimensioni 100. In questo caso, come è stato sottolineato, è probabile che si sta facendo qualcosa di strano. Ma è ancora possibile in modo carino con il metodo resize.
  • Un vettore di capacità 100. In questo caso probabilmente non si dovrebbe fare nulla in quanto i vettori non riducono la capacità AFAIR.E di sicuro non è necessario in quanto i vettori cambiano la sua capacità in modo dinamico.