2010-11-10 9 views
6

il mio codice:sta 'dando' un riferimento a 'questo' all'interno del costruttore ok?

Scene::Scene(const std::string &scene_file) : ambient_light(0, 0, 0), background(0, 0, 0){ 
    scene_parser parser(*this); 
    parser.parse(scene_file); 
} 

scene_parser è un amico di scena, e nel metodo parse si accede (r/w) i membri della scena. Ciò causerà problemi?

+0

Va notato da qualche parte che questo è OK finché si fornisce il puntatore 'this' all'interno del corpo del costruttore e non l'elenco di inizializzazione. –

+0

controlla anche cosa C++ faq-lite ha da dire: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7 – stefaanv

risposta

4

Nel tuo esempio particolare, non dovrebbero sorgere problemi.

In genere, il problema con l'assegnazione dei riferimenti this è che le vite dei due oggetti non si allineano esattamente e l'altro oggetto potrebbe tentare di accedere all'oggetto indicato dopo che è già stato distrutto.

Nel tuo esempio, l'oggetto scene_parser si trova nello stack, quindi il suo ciclo di vita termina alla fine del costruttore Scene. Non è possibile in alcun modo che possa tentare di accedere a un oggetto inesistente tramite il riferimento this fornito, quindi non possono sorgere problemi.

+3

No, ma se 'parser' richiama le funzioni' virtuali', non si otterrà l'effetto desiderato. Anche se * è * legale, potresti (e probabilmente dovresti) considerare un bug. –

+0

Questo è un potenziale trucco con la distribuzione di qualsiasi puntatore, nulla di specifico per i costruttori o il puntatore "this". Il vero trucco con la distribuzione di 'this' dal costruttore è che le funzioni dei membri della classe potrebbero essere chiamate prima che il costruttore termini di stabilire gli invarianti. –

+1

Non intendo sottoclassi Scene, quindi sembra tutto a posto. – Bwmat

8

Sì, è possibile fornire un riferimento a this. Tuttavia, di solito si desidera farlo quando l'altro oggetto utilizzerà il puntatore in un secondo momento. Il tuo caso d'uso sembra che userà lo Scene immediatamente, prima che il costruttore completi, che è una pendenza molto scivolosa.

Al momento, non si instaura alcuna invariante dopo aver chiamato parse, quindi dovrebbe essere ok, ma è anche fragile e facile per le modifiche future introdurre rotture.

+0

Buona risposta. Penso che dovresti includere alcune delle informazioni fornite nei commenti ad altre risposte, poiché sembra che ci siano alcune sottigliezze che dovrebbero essere affrontate. –

+2

@voodooclock: gli avvertimenti relativi alle funzioni virtuali in realtà non richiedono di passare il puntatore "this" a nessun altro oggetto. Puoi metterti nei guai chiamando le funzioni della classe dall'interno del costruttore. Inoltre, l'OP ha già indicato che 'Scene' è una classe terminale, quindi il tipo dinamico dell'oggetto non sarà un problema. –

+0

Ah, grazie per il chiarimento - stavo leggendo troppo in questo. –

1

Dipende.

All'interno del corpo del costruttore (ovvero, una volta eseguita la lista di inizializzazione), l'oggetto viene considerato "completamente costruito" fino al tipo corrente. Pertanto, è possibile che sia riferimento *this, ma qualsiasi chiamata di funzione virtual non utilizzerà le funzioni sovrascritte nelle classi derivate.

+2

Penso che tu abbia fatto il backward sulle chiamate alle funzioni virtuali, ma questa è una cosa importante da tenere presente. –

+0

@ Ben: hai ragione, ho digitato "base" anziché "derivato". –

0

Tutti i tuoi sottooggetti (membri e basi) sono costruiti dalla prima istruzione nel corpo del costruttore. Se il tuo oggetto si trova in uno "stato valido" (che fa parte della definizione della tua classe, a volte chiamato "invariante di classe"), puoi trattarlo come un oggetto completamente costruito e fare qualcosa con esso. Tuttavia, la ricerca virtuale funziona in modo leggermente diverso da quello che ci si potrebbe aspettare o richiedere: se si tratta di una classe base (e quindi questo oggetto è un sottooggetto di qualcos'altro), il tipo finale non è ancora stato "assegnato". Ad esempio, questo è un modo per chiamare metodi puramente virtuali e ottenere un errore di runtime (se questi metodi non hanno definizioni, comunque).

Una situazione più interessante è l'utilizzo di questo nell'inizializzatore del costruttore; questo ha alcuni avvertimenti, ma questo è anche prima del corpo del costruttore.

Problemi correlati