2009-12-24 16 views
10

È valido sviluppare una DLL in C++ che restituisca boost ai puntatori condivisi e li utilizzi come parametri?Va bene usare boost :: shared ptr nell'interfaccia DLL?

Quindi, è corretto esportare funzioni come questa?

1.) boost::shared_ptr<Connection> startConnection(); 
2.) void sendToConnection(boost::shared_ptr<Connection> conn, byte* data, int len); 

In particolare: fa il lavoro di conteggio di riferimento oltre i confini DLL o sarebbe il requisito di essere che EXE e DLL utilizzare lo stesso tempo di esecuzione?

L'intenzione è di superare i problemi con la proprietà dell'oggetto. Quindi l'oggetto viene cancellato quando sia dll che exe non lo fanno più riferimento.

risposta

10

Secondo Scott Meyers in Effective C++ (terza edizione), shared_ptrs sono sicuri oltre i limiti di dll. L'oggetto shared_ptr mantiene un puntatore al distruttore dalla DLL che lo ha creato.

Nel suo libro nel punto 18 afferma: "Una caratteristica particolarmente piacevole di TR1 :: shared_ptr è che usa automaticamente la sua per-puntatore deleter per eliminare un altro errore potenziale cliente, il" problema di cross-DLL . " Questo problema si verifica quando un oggetto viene creato utilizzando una nuova libreria (DLL) con collegamento dinamico ma viene eliminato in una DLL diversa. Su molte piattaforme, tali coppie di cross/DLL nuove/eliminate portano a errori di runtime . tr1 :: shared_ptr evita il problema, perché il suo deleter predefinito usa delete dalla stessa DLL dove viene creato tr1 :: shared_ptr. "

Tim Lesher ha un Gotcha interessante da guardare per, però, che egli cita here. È necessario assicurarsi che la DLL che ha creato il file shared_ptr non venga scaricata prima che il file shared_ptr diventi infine fuori ambito. Direi che nella maggior parte dei casi questo non è qualcosa da guardare, ma se crei dll che verranno accoppiati in modo approssimativo, ti consiglio di non usare shared_ptr.

Un altro svantaggio potenziale è assicurarsi che entrambe le parti siano create con versioni compatibili della libreria boost. Shared_ptr di Boost è rimasto stabile per molto tempo. Almeno dal 1.34 è stato compatibile con tr1.

+2

ATTENZIONE: se si sta collegando il CRT statico si avranno problemi. Ogni modulo collegato staticamente al CRT ottiene il proprio heap. Se tutti i moduli si collegano alla DLL CRT, condivideranno tutti un heap. – Zac

2

Le DLL di solito non possiedono risorse: le risorse sono di proprietà dei processi che utilizzano la DLL. Probabilmente stai meglio restituendo un puntatore semplice, che poi memorizzi in un puntatore condiviso sul lato chiamante. Ma senza ulteriori informazioni è difficile essere sicuri al 100% di questo.

4

A mio parere, se non è nello standard e non è un oggetto/meccanismo fornito dalla libreria, non dovrebbe essere parte dell'interfaccia della libreria. Puoi creare il tuo oggetto per fare il conteggio dei riferimenti, e forse usare boost sotto, ma non dovrebbe essere esplicitamente esposto nell'interfaccia.

2

Qualcosa da cercare se si espongono i puntatori raw da un'interfaccia dll. Ti costringe a utilizzare il CRT dll condiviso, la memoria allocata in un CRT non può essere deallocata in un CRT diverso. Se usi la dll condivisa CRT in tutti i tuoi moduli (dll's & exe) allora stai bene, tutti condividono lo stesso heap, se non lo farai attraverserai CRT e il mondo si scioglierà.

A parte questo problema, sono d'accordo con la risposta accettata. Probabilmente la factory di creazione non dovrebbe definire la proprietà & di gestione del ciclo di vita per il codice client.

+0

Come è possibile assicurarsi che exe e dll utilizzino la DLL condivisa CRT? Quali sono i flag del compilatore per questo? –

0

No, non lo è.

Il layout di boost::shared_ptr<T> potrebbe non essere lo stesso su entrambi i lati del limite della DLL. (Il layout è influenzato dalla versione del compilatore, dalle direttive di imballaggio e da altre opzioni del compilatore, nonché dalla versione effettiva del codice sorgente Boost.)

Solo "layout standard" (un nuovo concetto in C++ 11, correlato a il vecchio concetto "POD = plain old data") può essere tranquillamente passato tra moduli costruiti separatamente.