Come evitare di violare una regola di definizione in questo caso?

0

Abbiamo una classe di% C ++ Mutex esistente. Ha una funzione di debug per tracciare l'id del thread proprietario. Quindi ha una variabile membro per archiviare questo, ma poiché lo sviluppatore originale non vuole sprecare memoria, questo membro viene avvolto da una macro in un file di intestazione.

Questo file di intestazione è stato incluso in più progetti, alcuni binari sono sviluppati da altri reparti, quindi per quelle librerie non possiamo controllare l'opzione flag di compilazione, e non vogliamo questo accoppiamento strong.

// mutex.h
class Mutex
{
    ......
private:
    #ifdef _DEBUG
    int owner_thread_id_;
    #end
    ......
}

Recentemente siamo stati morsi da questo codice, a causa del danneggiamento della memoria causato dalla violazione della regola di una definizione.

Quindi, come possiamo implementarlo con i seguenti due requisiti:

  1. Non sprecare memoria perché è una classe di utilità e ampiamente utilizzata.
  2. Non violare la regola di una definizione.
posta ZijingWu 27.02.2015 - 03:32
fonte

1 risposta

5

Semplicemente. Non mescolare il codice creato con il debug con il codice creato senza.

Se la classe viene esportata dalla libreria a cui ti colleghi, è necessario:

  • Avere il debug e rilasciare la versione della libreria. Questo è quello che si fa sempre su Windows, dove anche il runtime standard ha due versioni del genere e sono incompatibili, quindi non c'è altro modo nella maggior parte dei casi. Questa è anche l'unica opzione se si tratta di una libreria di terze parti che non è possibile correggere.
  • Crea un flag di debug specifico per la libreria e mantieni un'intestazione di configurazione attorno a quella appropriata per il modo in cui hai costruito la libreria.
  • Lascia il campo incondizionatamente e metti solo il controllo condizionale (e assicurati che tutte le funzionalità rilevanti siano in funzioni che vengono compilate nella libreria, cioè definite in file .cpp).
  • Converti la classe per utilizzare l'idioma PImpl . Quindi i campi privati non influiscono su ABI.

Modifica annuncio 1: per impedire il collegamento con la libreria compilata con flag diversi rispetto al codice client, devi fare in modo che alcuni simboli vengano chiamati in modo diverso a seconda del flag (_DEBUG).

In C ++ il metodo più appropriato sembra mettere un po 'di codice in un subnamespace, fare in modo che quel subnamespace sia chiamato diversamente nella configurazione di debug e release, ad esempio qualcosa di

#ifdef _DEBUG
namespace library_internal_debug
#else
namespace library_iternal_release
#endif

e quindi importa i simboli nello spazio dei nomi principale con un condizionale simile usando:

namespace library {
#ifdef _DEBUG
    using library_iternal_debug::stuff;
#else
    using library_iternal_release::stuff;
#endif

In questo modo il client utilizzerà library::stuff in entrambe le configurazioni, ma i nomi dei simboli effettivi saranno diversi, quindi il collegamento con la costruzione errata fallirà. E a differenza della ridenominazione con il preprocessore, questo sarà opportunamente definito.

Devi solo applicarlo a uno o alcuni simboli importanti.

    
risposta data 27.02.2015 - 09:29
fonte

Leggi altre domande sui tag