std :: shared_ptr und dlopen (), vermeiden undefiniertes Verhalten

8

dlopen() ist eine C-Funktion, die zum dynamischen Laden von gemeinsam genutzten Bibliotheken zur Laufzeit verwendet wird. Das Muster, falls Sie nicht vertraut sind, ist also:

  • Rufen Sie dlopen("libpath", flag) auf, um ein void *handle für die Bibliothek
  • zu erhalten
  • Rufen Sie dlsym(handle, "object_name") auf, um eine void *object von der Bibliothek
  • zu erhalten
  • Mach was du willst mit object
  • Rufen Sie dlclose (handle) auf, um die Bibliothek zu entladen.

Dies ist in C ++ ein perfekter Anwendungsfall für den sogenannten Aliasing-Konstruktor von std::shared_ptr . Das Muster wird:

  • Erzeuge ein std::shared_ptr<void> handle von dlopen("libpath", flag) , das dlclose() aufruft, wenn sein Destruktor
  • aufgerufen wird
  • Konstruiere einen std::shared_ptr<void> object von handle und dlsym(handle, "object_name")
  • Jetzt können wir object wo auch immer wir wollen weitergeben und total handle vergessen; Wenn der Destruktor von object aufgerufen wird, wird dlclose() automatisch aufgerufen

Brilliantes Muster, und es funktioniert wunderbar. Ein kleines Problem. Das obige Muster erfordert eine Umwandlung von void* nach whatever_type_object_is* . Wenn sich "object_name" auf eine Funktion bezieht (was die meiste Zeit unter Berücksichtigung des Anwendungsfalles tut), ist dies ein undefiniertes Verhalten.

In C gibt es einen Hack, um das zu umgehen. Von der dlopen man-Seite:

%Vor%

was offensichtlich gut funktioniert, in C. Aber gibt es einen einfachen Weg, dies mit std::shared_ptr zu machen?

    
Arandur 16.03.2016, 15:57
quelle

3 Antworten

4
  

Das obige Muster erfordert eine Umwandlung von void * nach whatever_type_object_is *. Wenn sich "object_name" auf eine Funktion bezieht (was meistens unter Berücksichtigung des Anwendungsfalles geschieht), ist dies ein undefiniertes Verhalten.

Nun, das ist nicht ganz richtig, zumindest in C ++ wird es nur bedingt unterstützt.

5.2.10.8 sagt:

  

Das Konvertieren eines Funktionszeigers in einen Objektzeigertyp oder umgekehrt wird bedingt unterstützt. Die Bedeutung   Eine solche Konvertierung ist implementierungsdefiniert, außer dass eine Implementierung Konvertierungen unterstützt   beide Richtungen, Umwandlung eines Pr-Wertes eines Typs in den anderen Typ und zurück, möglicherweise mit anderer C-Qualifizierung,   soll den ursprünglichen Zeigerwert ergeben.

Wenn man also davon ausgeht, dass dlsym intern einen Funktionszeiger auf ein void* wirft, glaube ich, dass es in Ordnung ist, wenn man es einfach auf einen Funktionszeiger zurückwirft.

    
sbabbi 16.03.2016, 18:05
quelle
1

So etwas?

%Vor%

Ich bezweifle, dass Hack benötigt wird. Wie @sbabbi bemerkte, wird der Hin- und Rückweg zu void* bedingt unterstützt. Auf einem System, das dlsym verwendet, um Funktionszeiger zurückzugeben, wird es besser unterstützt.

    
Yakk 16.03.2016 18:18
quelle
0

Sie können eine Struktur erstellen, damit der Zeiger funktioniert und die Bibliothek behandelt:

%Vor%

Ich habe es nicht kompiliert, aber ich denke, es ist ausreichend, um die Idee zu zeigen.

    
Slava 16.03.2016 16:36
quelle