2010-11-05 18 views
5

La mia domanda è semplice, il prossimo codice è sicuro?liste di inizializzazione costruttore domanda ordine/assegnazione

struct Parent { 
    B* _a; 
    Parent(B* a) : _a(a) {} 
}; 

struct Child : public Parent { 
    B _b; 
    Child() : Parent(&_b), _b(2){}; 
}; 

int main() { 
    Child c; 
    return 0; 
} 

due punti in più:

  • Sono interessato alla parte di passare un riferimento a un oggetto membro al genitore.
  • Per sicurezza intendo che verrà assegnato lo _b (e il suo indirizzo di memoria) e che questo codice funzionerà indipendentemente dal compilatore che uso.

Grazie in anticipo.

chiarimento
dal sicuro io in realtà ha fatto sì che l'indirizzo di memoria era valido, dal momento che già sapevo che non era inizializzato.

altre note
Nel mio codice vero e proprio ho voluto conservare l'oggetto di tipo B come un puntatore alla sua classe base A, in questo modo:

struct Parent { 
    A* _a; 
    Parent(A* a) : _a(a) {} 
}; 

struct Child : public Parent { 
    B _b; 
    Child() : Parent(&_b), _b(2){}; 
}; 

int main() { 
    Child c; 
    return 0; 
} 

Il che, se ho ben capito AndreyT rispondere correttamente , è illegale. Credo che proverò a farlo in modo diverso, poiché questo approccio era soggetto a errori. (Potrei dimenticare che non potevo usare quel puntatore e fare qualcosa con esso nel mio prossimo refactoring).

+0

cosa sono A e B? Perché stai inizializzando un membro B * con A *. A deriva B? Inoltre, B ha un costruttore, che prende 'int' o qualcosa? –

+1

Presumibilmente il costruttore 'Parent' dovrebbe essere' Parent (B * a) '? –

+0

@Kiril Kirov typo, nel mio esempio iniziale A era una superclasse di B. Questo era per mostrare perché ne avrei avuto bisogno. –

risposta

8

Nel senso che descrivi, sì è sicuro: la memoria è allocata ed è perfettamente corretto passare quel puntatore al genitore. La memoria per Child::_b è in realtà parte integrante della memoria dell'intero Child. Non richiede alcuna "allocazione" esplicita aggiuntiva. Nel momento in cui viene invocato il costruttore Child::Child, la memoria è ovviamente già presente.

Tuttavia, la memoria a cui punta il puntatore può essere utilizzata solo in numero limitato (lo standard descrive in 3.8 cosa può e cosa non può essere fatto con esso), poiché l'oggetto a cui punta non è ancora stato inizializzato. Nel tuo esempio specifico, semplicemente memorizzi il puntatore. Questo è perfettamente OK.

Ma se, ad esempio, si desidera convertire quel puntatore in un tipo di classe base (supponendo per un secondo che B abbia qualche classe base), il codice sarebbe illegale. È illegale convertire i puntatori in oggetti non inizializzati ai loro puntatori di classe base (di nuovo, vedi 3.8).

1

Il costruttore padre verrà chiamato per primo e si passerà l'indirizzo di una variabile membro unitiliazed a tale costruttore. Non è sicuro.

edit:

penso AndreyT affermato in modo più chiaro e più vividamente il tipo di problemi che balzò in mente quando ho scritto la mia risposta. Questi sono i tipi di errori che non sono immediatamente percepibili. Il tipo che ti terrà sveglio di notte nel tentativo di capire dove si trova il puntatore che penzola nel tuo codice o dove si sta verificando il danneggiamento della memoria.

+0

Non funzionerà (se design non ideale) purché la classe base non utilizzi il membro della classe derivata nella sua costruzione? –

+0

Questo fu il mio pensiero immediato; ma sei sicuro che non sia sicuro (come in "indefinito) semplicemente passare l'indirizzo * * di una variabile non inizializzata? –

+3

Direi che non è sicuro in un certo senso che più tardi qualcuno potrebbe essere tentato di usare il puntatore nel costruttore di' A' Non è ovvio dal codice di 'A' perché questo non è legale.Lasciare tali botole nel codice non è sicuro –

6

L'ordine di inizializzazione è la seguente: "sicuro"

// Base classes: 
Parent(&_b) 

// Members: 
_b(2) 

// Constructor Body: 
Child() { } 

Se questo è sicuro dipende dalla vostra definizione di Secondo la tua definizione ("funzionerà?"), Sì, è sicuro. La durata di Child::_b inizia quando viene creato l'oggetto Child, quindi è possibile ottenere un puntatore e il puntatore si riferisce a un oggetto. Tuttavia, non è possibile utilizzare il valore puntato fino a quando non viene inizializzato _b, ovvero dopo che è stato restituito il costruttore della classe base, Parent.

Problemi correlati