dlopen()是C函数,用于在运行时动态加载共享库。因此,如果您不熟悉该模式,则为:

  • 调用dlopen("libpath", flag)以将void *handle获取到库
  • 调用dlsym(handle, "object_name")以从库
  • 中获取所需内容的void *object
  • object做你想做的事
  • 调用dlclose (handle)卸载库。

  • 在C++中,这是所谓的std::shared_ptr别名构造函数的理想用例。该模式变为:
  • std::shared_ptr<void> handle构造一个dlopen("libpath", flag),当其析构函数称为
  • 时将调用dlclose()
  • std::shared_ptr<void> objecthandle构造dlsym(handle, "object_name")
  • 现在,我们可以在任何需要的地方传递object,而完全不必考虑handle了;当object的析构函数被调用时,只要碰巧被调用,dlclose()就会被自动调用

  • 绚丽的图案,效果很好。不过,这是一个小问题。上面的模式需要从void*转换为whatever_type_object_is*。如果"object_name"引用了一个函数(考虑到用例,大多数情况下是这样),则这是未定义的行为。

    在C语言中,有一种解决方法。从dlopen手册页:
    // ...
    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");
    // ...
    

    显然在C中可以正常工作。但是有没有一种简单的方法可以使用std::shared_ptr做到这一点呢?

    最佳答案



    嗯,这并不是完全正确的,至少在C++中,它只是有条件支持的。

    5.2.10.8 说:



    因此,假设dlsym在内部执行的操作是将函数指针转换为void*,那么我相信,只要将其转换回函数指针即可。

    关于c++11 - std::shared_ptr和dlopen(),避免未定义的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36040814/

    10-15 14:35