Domanda

Se uso la parola chiave new nella mia libreria (che è costruita in modo diverso dalla mia app principale), quando la elimino nella mia app principale con elimina , c'è una possibilità che io possa ottenere un arresto anomalo / errore?

È stato utile?

Soluzione

sì, davvero. In particolare, vedi che i problemi con gli heap di debug / release sono diversi, anche se la tua libreria utilizza un posizionamento nuovo o qualsiasi heap personalizzato avrai un problema. Il problema Debug / Release è di gran lunga il più comune.

Altri suggerimenti

Dipende. Se stai parlando di una libreria statica, probabilmente starai bene - il codice verrà eseguito nello stesso contesto del programma principale, usando la stessa libreria di runtime C ++. Ciò significa che new e delete useranno lo stesso heap.

Se stai parlando di una libreria condivisa (una DLL), probabilmente non starai bene. Il codice in esecuzione nella DLL potrebbe utilizzare una libreria di runtime C ++ diversa, il che significa che il layout dell'heap sarà diverso. La DLL potrebbe utilizzare un heap completamente diverso.

La chiamata di delete (nel programma principale) su un puntatore allocato dalla DLL (o viceversa) comporterà (nella migliore delle ipotesi) un arresto immediato o (nella peggiore) una corruzione della memoria che impiegare un po 'di tempo per rintracciare.

Hai un paio di opzioni. Il primo è utilizzare il "metodo di fabbrica" modello per creare ed eliminare questi oggetti:

Foo *CreateFoo();
void DeleteFoo(Foo *p);

Questi non dovrebbero essere implementati nel file header.

In alternativa, puoi definire un metodo Destroy sull'oggetto:

class Foo
{
    ~Foo();

public:
    virtual void Destroy();
};

... di nuovo, non implementarlo nel file di intestazione. Lo implementeresti così:

void Foo::Destroy()
{
    delete this;
    // don't do anything that accesses this object past this point.
}

Nota che il distruttore di Foo è privato, quindi devi chiamare Foo :: Destroy .

Microsoft COM fa qualcosa di simile, in cui definisce un metodo Release che elimina l'oggetto quando il suo conteggio di riferimento scende a zero.

Sì, lo farai. Una soluzione semplice è fornire funzioni di creazione ed eliminazione nella libreria che possono essere richiamate dall'applicazione principale. La funzione Crea eseguirà il nuovo e restituirà un puntatore, che verrà successivamente passato alla funzione Elimina per l'eliminazione.

È un problema che ho visto solo su Windows.

I sistemi Unixish non hanno l'abitudine di forzare le librerie condivise a collegarsi a versioni diverse della stessa libreria all'interno dello stesso programma e tutti i simboli caricati sono visibili a livello globale. Ciò significa che se un oggetto viene allocato in una parte del codice ed eliminato in un'altra, entrambi utilizzano la stessa libreria di sistema per farlo.

Devo dire che questo problema che Windows crea con le sue varie DLL di runtime C è davvero fastidioso e innaturale per un programmatore C. Guarda la libreria C; ha funzioni come strdup che mallocano la stringa e si aspettano che il programmatore chiami free () su di essa. Ma fai la stessa cosa nella tua libreria su Windows e aspetta solo l'esplosione. Dovrai anche aspettare, perché non accadrà durante lo sviluppo ma solo dopo aver dato la DLL compilata a qualche altra povera linfa.

Old New Thing ha già trattato questo argomento . Fornisce inoltre un elenco delle principali soluzioni di Microsoft.

Hai perfettamente ragione sul fatto che ci sia un problema lì, ma per la maggior parte dei casi c'è una soluzione ancora più semplice rispetto alle altre risposte (finora) proposte. Puoi continuare a utilizzare il nuovo ed eliminarlo liberamente: tutto ciò che devi fare è sovraccaricare il nuovo ed eliminare per ogni classe nella tua libreria che potrebbe essere utilizzata oltre i confini della DLL.

Personalmente, ho appena definito una semplice classe per fornire le funzionalità necessarie:

class NewDelete
{
    public:
        void *operator new (size_t size);
        void operator delete (void *memory);
        void *operator new (size_t size, void *ptr);
        void operator delete (void *memory, void *ptr);
};

Finché queste quattro funzioni membro sono tutte definite nella stessa DLL, allora qualsiasi classe che deriva da questa classe è automaticamente "sicura per DLL". - new ed delete possono essere usati normalmente su di essi senza preoccuparsi dei confini della DLL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top