2010-09-21 9 views
5

Vengo da uno sfondo C# a C++. Supponiamo che abbia un metodo che crea un oggetto in un metodo sullo stack, quindi lo passo a un altro metodo di classi che lo aggiunge a un vettore memeber.Creazione di un oggetto sullo stack passando poi per riferimento a un altro metodo in C++

void DoStuff() 
{ 
    SimpleObj so = SimpleObj("Data", 4); 
    memobj.Add(so); 
} 

//In memobj 
void Add(SimpleObj& so) 
{ 
    memVec.push_back(so); //boost::ptr_vector object 
} 

Ecco le mie domande:

  1. Una volta che i metodi DoStuff estremità sarà il modo da andare fuori portata e essere spuntato dalla pila?
  2. memVec ha un puntatore a così ma è saltato fuori cosa succede qui?
  3. Qual è il modo corretto per passare gli oggetti dello stack ai metodi che li memorizzeranno come puntatori?

Mi rendo conto che questi sono probabilmente ovvi per un programmatore C++ con qualche esperienza.

Mark

+5

come nota a margine, "SimpleObj so = SimpleObj (" Data ", 4);" non è molto C++ ish, usa "SimpleObj so (" Data ", 4);" – Milan

+0

Grazie, ho ancora un po 'di sbornia C# .; – Mark

+0

@ milan1612: che purtroppo rimane ancora la notazione più portatile. il gruppo di compilatori C++ non riesce su quest'ultimo, [analogamente al caso] (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.21). – Dummy00001

risposta

8
  1. Sì.
  2. Il puntatore rimane "vivo", ma punta a un oggetto non più esistente. Ciò significa che la prima volta che provi a dereferenziare tale puntatore andrai in un comportamento indefinito (probabilmente il tuo programma andrà in crash, o, peggio, continuerà a funzionare dando risultati "strani").
  3. Semplicemente non farlo se vuoi mantenerli dopo la funzione restituita. Ecco perché vengono utilizzati l'allocazione dell'heap e i contenitori che memorizzano copie di oggetti.

Il modo più semplice per ottenere ciò che si sta cercando di fare sarebbe quella di memorizzare una copia degli oggetti in un normale container STL (ad esempio std::vector). Se tali oggetti sono pesanti e costosi da copiare, si consiglia di allocarli nell'heap archiviandoli in un contenitore di puntatori intelligenti adeguati, ad es. boost::shared_ptr (vedere l'esempio in @Space_C0wb0y's answer).

Un'altra possibilità è utilizzare lo boost::ptr_vector in associazione con boost::ptr_vector_owner; quest'ultima classe si occupa di "possedere" gli oggetti memorizzati nell'associato ptr_vector e di eliminare tutti i puntatori quando esce dall'ambito. Per ulteriori informazioni su ptr_vector e ptr_vector_owner, è possibile dare un'occhiata a this article.

+0

Grazie, voglio evitare di copiare oggetti in giro, ma anche evitare di dover gestire la memoria nello heap, quindi penso che guarderò le ultime due opzioni. – Mark

+0

Dato che vieni da C#, ti consiglio di dare un'occhiata anche agli altri puntatori intelligenti forniti da boost e di imparare dove ognuno di loro è meglio utilizzato. La gestione della memoria in C++ non è facile come in C#, ma usando i puntatori intelligenti giusti diventa quasi automatico. A proposito, se la mia risposta o un altro risolvono il problema, puoi considerare di contrassegnarlo come "accettato". –

+0

Sì, sto facendo uso di Boost lib e il puntatore intelligente, semplicemente non li ho capiti completamente, ma tu mi hai illuminato, grazie. – Mark

3

Per raggiungere il tuo obiettivo, è necessario utilizzare un shared_ptr:

void DoStuff() 
{ 
    boost::shared_ptr<SimpleObj> so(new SimpleObj("Data", 4)); 
    memobj.Add(so); 
} 

//In memobj 
void Add(boost::shared_ptr<SimpleObj> so) 
{ 
    memVec.push_back(so); // std::vector<boost::shared_ptr<SimpleObj> > memVec; 
} 
+0

Ok questo ha senso, quindi il conteggio dei riferimenti sarà uno sul ptr una volta aggiunto al vettore, quindi non sarà distrutto. – Mark

+0

@Mark: Sì. E quando il contenitore viene distrutto, il conteggio dei riferimenti per ogni 'shared_ptr' nel contenitore verrà diminuito di uno (e gli oggetti verranno eliminati sul posto se raggiunge 0). –

+0

Vorrei raccomandare 'unique_ptr' invece di' shared_ptr' se stai usando C++ 0x - c'è meno overhead. Invece di fare copie che aumentano il numero di riferimenti, viene semplicemente spostato. – AshleysBrain

0

Per memorizzare un puntatore su un oggetto, è necessario creare con nuovo. Altrimenti scomparirà quando si esce dal campo di applicazione.
La soluzione più semplice al tuo problema come presentato qui sarebbe quella di utilizzare std :: vector invece di boost :: ptr_vector, perché in questo modo il push_back sarebbe copiare l'oggetto nel vettore

1

Si, il tuo modo oggetto sarà spuntato fuori lo stack una volta che la tua funzione lascia lo scope. Dovresti creare un oggetto heap usando new e aggiungere un puntatore a quello nel tuo vettore.

Come detto prima, il puntatore nel vostro vettore punterà a qualcosa di indefinito una volta che il prima funzione esce dallo scope

1

Questo codice non verrà compilato perché dentro la funzione Add si sta cercando di provare a spingere un l'intero oggetto in un vettore che si aspetta un puntatore a un oggetto.

Se invece si dovesse prendere l'indirizzo di quell'oggetto e spingerlo sul vettore, sarebbe pericoloso poiché l'oggetto originale sarebbe presto fuoriuscito dalla pila e il puntatore memorizzato avrebbe puntato alla memoria non inizializzata.

Se si utilizza un vettore normale anziché un vettore puntatore, la chiamata push_back copierà l'intero oggetto anziché il puntatore e quindi sarebbe sicuro. Tuttavia, questo non è necessariamente efficiente, e l'approccio 'copia tutto' non è probabilmente intuitivo per qualcuno dai mondi C#, Java o Python.

Problemi correlati