dlopen()
è una funzione C utilizzata per caricare dinamicamente le librerie condivise in fase di esecuzione. Il modello, nel caso in cui non hai familiarità, è dunque:std :: shared_ptr e dlopen(), evitando comportamenti non definiti
- chiamata
dlopen("libpath", flag)
per ottenere unvoid *handle
alla biblioteca - chiamata
dlsym(handle, "object_name")
per ottenere unvoid *object
alla cosa che si vuole dalla libreria - Do cosa vuoi con
object
- Chiama
dlclose (handle)
per scaricare la libreria.
Questo è, in C++, un caso d'uso perfetto per la cosiddetta aliasing costruttore di std::shared_ptr
. Il modello diventa:
- costruire un
std::shared_ptr<void> handle
dadlopen("libpath", flag)
che chiameràdlclose()
quando il suo distruttore viene chiamato - costruire un
std::shared_ptr<void> object
dahandle
edlsym(handle, "object_name")
- Ora possiamo passare
object
dove vogliamo, e completamente dimenticarehandle
; quando distruttoreobject
s' è detto, ogni volta che sembra essere,dlclose()
saranno chiamati automagically
brillante modello, e funziona meravigliosamente. Un piccolo problema, però. Il modello sopra richiede un cast da void*
a whatever_type_object_is*
. Se "object_name"
si riferisce a una funzione (che la maggior parte delle volte fa, considerando il caso d'uso), questo è un comportamento non definito.
In C, c'è un trucco per aggirare questo. Dalla pagina dlopen
man:
// ...
void *handle;
double (*cosine)(double);
// ...
handle = dlopen("libm.so", RTLD_LAZY);
// ...
/* Writing: cosine = double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
// ...
che funziona, ovviamente, più che bene, in C. Ma c'è un modo semplice per fare questo con std::shared_ptr
?
perché hai bisogno di 'std :: shared_ptr' nel poointer, restituito da dlsym? – Slava
@Slava: per garantire la durata (non chiamare 'dlclose' quando c'è quel puntatore). – Jarod42
Il costruttore aliasing di 'std :: shared_ptr' consente a due' std :: shared_ptr's di condividere la stessa "condizione di chiusura" (il mio termine, non ufficiale) senza indicare lo stesso oggetto o lo stesso tipo. L'uso di 'std :: shared_ptr' per il valore restituito da' dlsym() 'mi procura questo vantaggio: la durata della libreria è legata alla durata di' object'. – Arandur