2012-04-06 10 views
7

So che le variabili allocate su quella pila di una funzione diventano inaccessibili quando la funzione termina l'esecuzione. Tuttavia, i tipi di vettore allocano i loro elementi nell'heap indipendentemente dal modo in cui sono allocati. Ad esempio,È possibile passare un vettore allocato sullo "stack" dalla funzione alla funzione?

vector<int> A; 

allocherà spazio per i suoi elementi nell'heap anziché nella pila.

La mia domanda è, assumere Ho il seguente codice:

int main(int argc, char *argv[]) { 
    // initialize a vector 
    vector<int> A = initVector(100000); 

    // do something with the vector... 

    return 0; 
} 


// initialize the vector 
vector<int> initVector(int size) { 
    vector<int> A (size); // initialize the vector "on the stack" 

    // fill the vector with a sequence of numbers... 
    int counter = 0; 
    for (vector<int>::iterator i = A.begin(); i != A.end(); i++) { 
     (*i) = counter++; 
    } 

    return A; 
} 

Avrò problemi di accesso di memoria quando si utilizza il vettore A nella funzione principale? Ho provato questo più volte e hanno funzionato tutti normalmente, ma ho paura che questa potrebbe essere solo fortuna.

Il modo in cui lo vedo è che il vettore A assegna i suoi elementi all'heap, ma ha alcuni parametri "generali" (forse la dimensione del vettore) allocati nello stack stesso. Pertanto, l'utilizzo del vettore nella funzione principale potrebbe causare un problema di accesso alla memoria se questi parametri vengono sovrascritti da un'altra allocazione. Qualche idea?

+1

Dalla tua logica, 'int add (int a, int b) {int r = a + b; return r} 'dovrebbe avere lo stesso problema che si sospetta per il proprio' initVector' ... – delnan

+0

'vector A (size);' => 'A' risiede nello stack ma le posizioni di memoria che sta puntando risiedono nell'heap. Le posizioni di memoria contigue del 'size' sono in heap, mentre la classe vector tiene il puntatore all'elemento di inizio sull'heap. Vediamo se qualcuno mi corregge. – Mahesh

+0

TBH, sono stato un po 'confuso anche da questo genere di cose. Ogni volta che ho avuto qualche dubbio, ho anche assegnato il vettore, ad esempio: 'vector * a; a = nuovo vettore ; ' e quindi restituito il puntatore. –

risposta

1

Sì, funzionerà normalmente perché la memoria per gli elementi è allocata e questo è ciò che verrà utilizzato per creare la variabile vector<int> A =. Tuttavia, per quanto riguarda le prestazioni, non è la migliore idea.

vorrei suggerire cambiando la funzione di essere il seguente però

void initVector(vector<int>& a, int size) 

Per ulteriori riferimenti sul loro utilizzo, si prega di consultare Returning a STL vector from a function… e [C++] Returning Vector from Function.

Per un ulteriore riferimento sulle prestazioni (usando C++ 11), si prega di consultare Proper way (move semantics) to return a std::vector from function calling in C++0x

+0

RVO probabilmente renderebbe inutile quella modifica suggerita. Ma è comunque una buona pratica. –

+0

Grazie per i collegamenti. Sono d'accordo che questo è un metodo migliore. Ho sempre avuto dei dubbi su come funziona la classe vettoriale. – alguru

+0

@josephthomas Se uso il tuo metodo (cioè passando il vettore per riferimento), allora sarò costretto ad assegnare il vettore usando 'a = new vector '? O c'è un modo per aggirare questo? – alguru

4

Quando non "ritorni A;" tu ritorni per valore, così ottieni una copia del vettore - C++ crea una nuova istanza e chiama copy constructor o operator = su di esso. Quindi in questo caso non importa dove è stata allocata la memoria poiché è necessario copiarla comunque e distruggere la vecchia copia (nonostante alcune ottimizzazioni possibili).

I dati nel vettore (e in tutti gli altri contenitori STL) vengono spostati in base al valore, quindi si memorizza la copia dei numeri interi, non i puntatori a essi. Ciò significa che i tuoi oggetti possono essere copiati più volte in qualsiasi operazione di contenitore e devono implementare correttamente un costruttore di copia e/o un operatore di assegnazione. C++ genera quelli per te di default (solo chiamando copy ctor su tutte le tue variabili membro), ma non sempre fanno la cosa giusta.

Se si desidera archiviare i puntatori in un contenitore STL, considerare l'utilizzo di wrapper del puntatore condivisi (std :: shared_ptr o boost :: shared_ptr). Assicureranno che la memoria sia gestita correttamente.

0

Il vettore C++ contiene effettivamente due parti di memoria collegate a un singolo puntatore. Il primo è in pila e il 2 ° in heap. Quindi hai caratteristiche sia di stack che di heap in un singolo oggetto.

std::vector<int> vec; 
vec.push_back(10); 
vec.push_back(20); 
vec.push_back(30); 
std::cout << sizeof(vec) << std::endl; 

Una volta che si esegue il codice, si noterà che l'area di stack non contiene gli elementi, ma esiste ancora. Quindi, quando si passa il vettore da una funzione all'altra, è necessario manipolare le aree di stack e il vettore verrà copiato come qualsiasi altro oggetto basato su stack.

Problemi correlati