2014-07-21 9 views
8

Nel libro Stroustrup (. Il C++ linguaggio di programmazione 4a ed, §17.5.1, pag 508) ho trovato il seguente esempio di un costruttore di copia per un semplice Matrix classe:Perdita di risorse nell'esempio Stroustrup con std :: uninitialized_copy?

template < class T > 
Matrix:: Matrix(const Matrix& m) // copy constructor 
    : dim{ m.dim }, 
     elem{ new T[ m.size() ] } 
{ 
    uninitialized_copy(m.elem, m.elem+m.size(), elem); // copy elements 
} 

(dove elem è il puntatore all'array di elementi T, dichiarato come T* elem;).

Ho due domande su questo costruttore di copia:

  1. perché il metodo di default prima costruire una serie di elementi m.size(), solo per sovrascrivere nel corpo con la chiamata uninitialized_copy?

  2. con l'inizializzazione elem{ new T[ m.size() ] }, il costruttore di T è chiamato m.size() volte. Tuttavia, l'algoritmo uninitialized_copy nel corpo non chiama il distruttore T prima di costruire il nuovo array nella stessa area. Si tratta di una potenziale perdita di risorse? (Nota: non una perdita di memoria, una perdita di risorse! Ad esempio, se T acquisisce un lock o un descrittore di file nel Ctor e lo rilascia nel Dtor).

Grazie

risposta

3

Sì, questo è chiaramente un errore; il codice deve utilizzare copy anziché . Dal momento che il è di solito un tipo banale, la perdita di risorse viene in genere evitata, ma è comunque un bug.

Per rispondere alla tua prima domanda, è più semplice scrivere il default inizializzatore copia membro costruttore di costruire un array, come che consente al costruttore di copia di utilizzare lo stesso metodo di assegnazione semplice come il costruttore (n, m). Sarebbe più efficiente allocare un'area di memoria non inizializzata e costruire in essa, ma ciò complicherebbe i costruttori e i distruttori, il che andrebbe a detrimento dal punto della classe Matrix. Il modo più idioma per scrivere questo sarebbe con Matrix che avvolge una classe di array dinamico (vettore a dimensione fissa), ad esempio dynarray (probabilmente post-C++ 14 TS).

Come ha sottolineato Puppy, il costruttore di copie ha una perdita di memoria se il suo corpo getta. Ciò avverrebbe indipendentemente dal fatto che sia utilizzato copy o uninitialized_copy. Stroustrup dice // simplified (no error handling) prima nella classe, quindi questo può essere giustificato.

Ad ogni ipotesi, direi che il modo in cui questo errore si è insinuato è che Stroustrup utilizza uninitialized_copy altrove nel libro, in particolare nella sua classe vettoriale. Non ho accesso alle edizioni precedenti ma ho il sospetto che questo sia stato aggiunto per sostituire un ciclo e provare/catturare il blocco nel costruttore di copia vettoriale, e Matrix è stata modificata in modo simile senza una considerazione completa.

Non è mostrato a Stroustrup list of errata per la 4a edizione, ma potrebbe già essere a conoscenza (la pagina di errata è stata aggiornata l'ultima volta a novembre 2013). Se hai voglia di inviarlo via email con questo errore, dovresti assolutamente farlo!

+2

Questo non è vero- se il costruttore di copie fallisce, il distruttore non verrà chiamato. Ciò porta ad un problema di perdita di memoria/eccezione di sicurezza più problematico se il costruttore di copie * non * fallisce, assumendo che 'elem' sia un' T * '. – Puppy

+0

@Puppy hai completamente ragione; questo è il motivo per cui non scrivo mai classi di contenitori. – ecatmur

+2

Se 'elem' fosse un' unique_ptr ', sarebbe perfettamente sicuro. – Puppy

5

Sono l'autore della domanda.
Ho fatto le mie due domande a Bjarne Stroustrup via e-mail e ho pensato di condividere le sue risposte qui.

Lui gentilmente (e poco :-) risposero:

  1. Si tratta di una svista e uno spreco.
  2. Sì, se un tipo T detiene risorse, si tratta di una perdita di

Ha scritto anche che ha intenzione di correggere l'errore.

Problemi correlati