2009-08-27 18 views
7

Capisco che le allocazioni di memoria effettuate in una DLL e successivamente liberate in un'altra possono causare problemi di sorta, in particolare per quanto riguarda il CRT. Questi tipi di problemi sono particolarmente problematici quando si tratta di esportare container STL. Abbiamo sperimentato questo tipo di problemi prima (durante la scrittura dei plugin personalizzato Adobe che collegavano con le nostre biblioteche) e abbiamo lavorato intorno a questi problemi definendo la nostra allocatore che usiamo in tutti i nostri contenitori, ad esempio:Allocazione di memoria e deallocazione attraverso i contorni delle DLL

typedef std::vector < SessionFields, 
     OurAllocator <SessionFields> > 
     VectorSessionFields; 

typedef std::set < SessionFields, 
     std::less <SessionFields>, 
     OurAllocator <SessionFields> > 
     SetSessionFields; 

Questo ha funzionato bene durante il passaggio di tipi al/dal nostro codice, tuttavia abbiamo riscontrato un problema in quanto dovremmo ora chiamare una funzione nell'SDK di Adobe che restituisce un vettore popolato che causa un arresto anomalo quando esce dall'ambito .

Ovviamente, è un problema con l'allocazione della memoria nell'SDK di Adobe che appartiene a un altro heap quando finalmente è stato liberato nel mio codice. Quindi penso che forse potrei fare qualcosa di intelligente come in qualche modo sovrascrivere o esportare l'allocatore usato nel loro SDK in modo da poterlo usare per ripulire i contenitori restituiti dalle loro funzioni.

Sto anche cercando di scrivere un involucro o una sorta di strato thunking cui contenitori STL sarebbero schierate in modo sicuro tra il mio codice e l'SDK (anche se questo suona molto disordinato).

In alternativa, sto anche utilizzando GetProcessHeaps per identificare l'heap utilizzato dall'SDK e provare a liberare questo heap anziché l'heap predefinito.

Qualcuno ha qualche consiglio su come possiamo risolvere questo problema?

risposta

0

Si potrebbe provare a cercare se ci sono regole C++ formali per ciò che accade quando un'eccezione viene lanciata in una DLL e catturata in un'altra e quindi esce dall'ambito - sembra molto simile. Per le eccezioni, I penso a che è necessario fornire un costruttore di copia con una firma speciale, anche se non sono sicuro ora esattamente di cosa si tratta.

6

Ironia della sorte, Adobe Source Libraries ha una classe adobe::capture_allocator che è stata scritta appositamente per questo tipo di protezione della DLL. Il modo in cui funziona è catturare il locale new e a questo punto viene istanziato e portarli entrambi in giro per la vita dell'oggetto. (Vedere adobe::new_delete_t per dettagli su come eseguire questa operazione, in particolare l'implementazione here.) Le allocazioni vengono eseguite con la routine acquisita delete, garantendo che indipendentemente da dove si stia eliminando l'appropriato delete.

potete vedere capture_allocator utilizzati in tutto il version_1 i tipi di file Biblioteche Adobe, ad esempio adobe::any_regular_t e adobe::copy_on_write. capture_allocator dovrebbe essere compatibile anche con tutti i tipi di container STL.

Aggiornamento: capture_allocator non è conforme allo standard perché mantiene lo stato. Questo non dovrebbe essere un grande ostacolo alla sua usabilità, ma significa che il suo uso non è garantito per funzionare con contenitori conformi agli standard.

+0

Questa è una tecnica molto comune, l'ho vista anche in C, dove una libreria richiede agli utenti di fornire un callback allocazione/de-allocazione tramite una sorta di punto init() della libreria. – Justin

2

Al momento stiamo lavorando su una dll che espone la funzionalità C++ tramite un'interfaccia C (per motivi di C# è in grado di utilizzare la suddetta dll).

per esempio: il DLL ha una struttura myStruct_s l'interfaccia espone le seguenti funzioni:

interface.h

#ifndef INTERFACE_TYPES_H 
# error Please include interace_types.h 
#endif 
    myStruct_s * CreateTheStruct() { return new myStruct_s(); } 
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; } 
    void DoSomethingToTheStruct(myStruct_s * the_struct); 

interface_types.h

#define INTERFACE_TYPES_H 
struct myStruct_s; // fwd declaration 
#endif 

interfaccia .cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS) 
#include<TheRealFileContainingTheRealMyStruct_s.h> 
// handle the .h's functions here 
#endif 

comeOutsideCppFile.cpp

#include "interface_types.h" 
#include "interface.h" 

void main() 
{ 
    myStuct_s * x = CreateTheStruct; 
    DoSomethingToTheStruct(x); 
    DestroyTheStruct(x); 
} 

Quanto sopra è un abbozzo di come funziona la nostra roba, in fondo: Qualunque sia la dll espone esigenze da: Creato, Handled, distrutto dll- lato

Questo codice non è preciso al 100% !!!

Inoltre, tieni presente che se stai utilizzando una dll C++ pura, probabilmente hai bisogno dello stesso compilatore con le stesse impostazioni di quello usato per compilare la dll.

+1

@Maciek: interface.h dovrebbe contenere funzioni NON inline. Facendo in linea le funzioni, verranno compilate nell'unità di compilazione di comeOutsideCppFile.cpp, che rovina il concetto. – shojtsy

Problemi correlati