2009-12-10 5 views
8

Ho una DLL che deve accedere ai dati memorizzati nei contenitori STL nell'applicazione host. Poiché il C++ non ha ABI standard e voglio supportare diversi compilatori, l'interfaccia tra l'applicazione e la DLL deve fondamentalmente rimanere semplice-vecchia-dati.Come esporre l'elenco STL oltre il limite della DLL?

Per i vettori questo è relativamente semplice. Si può semplicemente restituire il blocco di memoria del vettore, perché è garantito per essere contigious:

// To return vector<int> data 
virtual void GetVectorData(const int*& ptr, size_t& count) const 
{ 
    if (!vec.empty()) 
     ptr = &(vec.front()); 

    count = vec.size(); 
} 

Ora la DLL può avere sicuro accesso in sola lettura ai dati del vettore tramite l'interfaccia. La DLL può anche avvolgere questo per copiare il contenuto in un vettore anche per se stesso.

E per quanto riguarda le liste STL (e gli accessori)? C'è un altro modo semplice per consentire l'accesso tramite un limite DLL? O dovrò ricorrere a qualche tipo di interfaccia GetFirst()/GetNext()? Potrei aver bisogno di farlo per molte liste, quindi sarebbe bello avere una soluzione semplice come quella dei vettori.

risposta

7

Forse è possibile passare qualcosa come "maniglie" per elencare/deerare gli iteratori? Questi tipi di handle sarebbero opachi e dichiarati in un file di intestazione che spediresti agli utenti. Internamente, è necessario mappare i valori di handle per elencare/deerare gli iteratori. In sostanza, l'utente dovrebbe scrivere codice come:

ListHandle lhi = GetListDataBegin(); 
const ListHandle lhe = GetListDataEnd(); 

while (lhi != lhe) 
{ 
    int value = GetListItem(lhi); 
    ... 
    lhi = GetNextListItem(lhi); 
} 
1

l'interfaccia tra l'applicazione e DLL ha sostanzialmente rimanere plain-old-dati.

Non necessariamente. Devi essere sicuro che venga utilizzata la stessa versione del compilatore. Inoltre, le impostazioni di build che influiscono sul layout degli oggetti STL sono esattamente le stesse tra la DLL e l'applicazione.

Se dovessi rilasciare la dll in natura, hai ragione a preoccuparti di esporre STL oltre i confini delle dll. Se, tuttavia, tutto è sotto il tuo controllo e puramente interno (o se puoi forzare rigidamente le impostazioni/compilatore di compilazione di terze parti) dovresti stare bene.

+0

Hai ragione che potrei farla franca se tutte le impostazioni di compilazione sono uguali. Ma questo è per un'architettura plugin e mi piacerebbe supportare diversi compilatori. Ho modificato la domanda per chiarire questo. – AshleysBrain

+0

Sono d'accordo con questo, ma forse dovresti sottolineare che non è solo il layout: il codice deve essere stato compilato con la stessa versione del compilatore, in modo che le implementazioni di metodi come new e delete corrispondano. –

+0

Se imponi rigidamente le impostazioni di compilazione/le versioni del compilatore e tutto è sotto il tuo controllo, qual è il vantaggio delle DLL rispetto all'utilizzo di librerie statiche e il collegamento di tutto in un unico eseguibile? –

10

È possibile passare oggetti STL tra le DLL e supportare diversi compilatori se siete attenti dove si crea un'istanza di ogni tipo STL. Sono necessari alcuni "macro DLLEXPORT" intelligenti: utilizzo il seguente set per supportare VC e gcc con successo.

#ifdef WIN32 
#ifdef MYDLLLIB_EXPORTS  // DLL export macros 
#define MYDLLLIB_API __declspec(dllexport) 
#define MYDLLLIB_TEMPLATE 
#else 
#define MYDLLLIB_API __declspec(dllimport) 
#define MYDLLLIB_TEMPLATE extern 
#endif 
#else      // Not windows --- probably *nix/bsd 
#define MYDLLLIB_API 
#ifdef MYDLLLIB_EXPORTS 
#define MYDLLLIB_TEMPLATE 
#else 
#define MYDLLLIB_TEMPLATE extern 
#endif 
#endif // WIN32 

Durante la compilazione della DLL, definire MYDLLLIB_EXPORTS. Nella DLL si può quindi istanziare ogni tipo STL che si desidera utilizzare, ad esempio, elenchi o vettori di stringhe

MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::vector<std::string>; 
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::list<std::string>; 

consumatori di DLL (che non hanno MYDLLLIB_EXPORTS definiti) sarà poi vedere

extern template class __declspec(dllimport) std::vector<std::string>; 

e utilizzare il codice binario esportato dalla DLL anziché creare un'istantanea.

+0

Questa è una soluzione molto interessante - dovrei fare lo stesso per std :: vector :: iterator e std :: list :: iterator? È lo stesso modo per le classi STL che utilizzano DLL da un host EXE? – AshleysBrain

+0

Non è necessario creare un'istanza degli iteratori perché quando si crea un'istanza di una classe di contenitore stl specifica si ottiene anche il codice per tutte le classi all'interno della classe contenitore. Non so di consumare classi STL da un host EXE - Non l'ho provato personalmente, quindi se vuoi seguire questo metodo dovrai fare un po 'di sperimentazione con un semplice test. – mcdave

+2

Eccolo in MSDN: http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q168958 – k06a