2014-09-12 34 views
5

Ho c-Structure che voglio incorporare in una classe cpp senza avvelenare il mio spazio dei nomi globale, quindi non voglio includere il c-header.QScopedPointer, boost :: scoped_ptr - perché lamentarsi di tipi incompleti?

Ecco perché voglio utilizzare un puntatore a scope intelligente (QScopedPointer o boost::scoped_ptr) con un nome di struttura dichiarata in avanti.

Quello che non capisco è l'implementazione di entrambi menzionato puntatori di ambito che cade sulla compilazione:

spinta:

errore C2027: uso di tipo non definito 'xxx'

template<class T> inline void checked_delete(T * x) 
{ 
    // intentionally complex - simplification causes regressions 
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here 
    (void) sizeof(type_must_be_complete); 
    delete x; 
} 

e lo stesso in Qt:

errore C2027: uso di tipo non definito 'xxx'

template <typename T> 
struct QScopedPointerDeleter 
{ 
    static inline void cleanup(T *pointer) 
    { 
     // Enforce a complete type. 
     // If you get a compile error here, read the section on forward declared 
     // classes in the QScopedPointer documentation. 
     typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; // < here 
     (void) sizeof(IsIncompleteType); 

     delete pointer; 
    } 
}; 

La documentazione fa riferimento non mi ha aiutato. dice che il distruttore della classe dichiarata avanti non deve essere in linea e deve essere disponibile ad ogni possibile istanziazione della pulizia del puntatore ad ambito. Ma la mia struttura c non ha un distruttore.

Così ho 2 domande:

  1. Perché questo controllo a tutti? Perché sembra irrilevante sapere la dimensione per chiamare delete.
  2. Come affrontare questo?

risposta

8
  1. Il tipo di oggetto che viene tenuto in puntatore intelligente deve essere noto nel luogo in cui viene destructed, in modo corretto distruttore di oggetto conservato può essere chiamato puntatore intelligente
  2. fa la classe (quella che detiene intelligente pointer) ha distruttore? Se no, aggiungine uno nel tuo file cpp. Altrimenti il ​​compilatore tenta di aggiungerne uno quando vede la definizione della classe e non può farlo perché il distruttore del puntatore intelligente tenta di accedere a un tipo sconosciuto.
+0

ah ho trascurato la piccola linea con la definizione del distruttore virtuale vuoto nel corpo delle dichiarazioni di classe. dopo averlo spostato nel cpp l'errore era sparito. –

6

my c-Structure non ha un distruttore.

Per una cosa, No. La tua struct in realtà ha un distruttore - implicitly-declared destructor.


In ogni caso, andiamo avanti.

delete pointer; 

Quando si compila questo codice, dovremmo chiamare il distruttore di *pointer. Tuttavia, se *pointer è un tipo incompleto, non possiamo sapere il distruttore da chiamare. In questo caso, standard [expr.delete] dice che causa il comportamento non definito .

Se l'oggetto eliminato ha tipo classe incompleta al punto di delezione e la classe completa ha un distruttore non banale o una funzione deallocazione, il comportamento è indefinito.

Come si può vedere, se la vostra struct non ha distruttore non banale o una funzione deallocazione (operator delete specifici per classe), non è UB. Tuttavia, è probabile che tu possa aggiungere un distruttore nella tua struct: tu eseguirà do. Se lo fai senza correggere questo punto, diventa davvero un bug bug. (Il compilatore non deve segnalarlo, è solo UB, non codice illegale.) Quindi è non considerato come una buona pratica.

Per questo motivo, l'eliminazione di tipi incompleti è davvero ciò che dovremmo evitare. Per evitare ciò, usiamo questo trucco.

typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here 
(void) sizeof(type_must_be_complete); 

Dal sizeof(T) è il codice illegale se T è tipo incompleto, in modo che possa ridurre l'errore di compilazione prima che il programma va essere pazzo a causa di UB.

Consiglio vivamente di includerlo solo a fronte di una più lenta velocità di elaborazione; Sebbene la tua struct sia banale e non abbia operator delete, possono essere aggiunti senza correzione, il che causa UB.

+0

la struttura proviene da un'intestazione "extern" C "{}' e dall'implementazione da una libreria C pura collegata separatamente. come potrebbe esserci un distruttore. ma sono d'accordo che, naturalmente, per le classi regolari il loro contenuto deve essere noto per decidere se c'è qualche distruttore o se liberare direttamente la memoria. –

+0

@vlad_tepesch è la libreria una libreria esterna di terze parti (ad es. Libgmp) o la tua libreria che viene scritta adesso? – ikh

+0

la lib è nelle mie mani ma era solo ipotetico mostrare che è possibile non avere alcun distruttore e nessuna possibilità di crearne uno implicitamente (per esempio se la libreria stessa nasconde la definizione della struttura e fornisce una funzione di fabbrica). come il mio commento sull'altra risposta dice: potrei trovare ed eliminare il problema. –