std :: shared_ptr和dlopen(),避免未定义的行为

Ara*_*dur 9 c++ shared-libraries shared-ptr undefined-behavior c++11

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

  • 打电话dlopen("libpath", flag)到void *handle图书馆
  • 打电话从图书馆dlsym(handle, "object_name")得到void *object你想要的东西
  • 做你想做的事 object
  • 调用dlclose (handle)卸载库.

在C++中,这是所谓的别名构造函数的完美用例std::shared_ptr.模式变为:

  • 构造一个std::shared_ptr<void> handlefrom dlopen("libpath", flag)将在调用dlclose()析构函数时调用
  • 构建一个std::shared_ptr<void> objectfrom handle和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");
// ...
Run Code Online (Sandbox Code Playgroud)

这显然在C中工作正常.但有一个简单的方法来做到这一点std::shared_ptr?

sba*_*bbi 4

上面的模式需要从 void* 到whatever_type_object_is* 的转换。如果“object_name”引用一个函数(考虑到用例,大多数情况下都是这样),这是未定义的行为。

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

5.2.10.8说:

有条件地支持将函数指针转换为对象指针类型,反之亦然。这种转换的含义是实现定义的,但如果实现支持双向转换,则将一种类型的纯右值转换为另一种类型并返回(可能使用不同的 cv 限定)将产生原始指针值。

因此,假设dlsym内部所做的是将函数指针强制转换为 a void*,我相信如果将其强制转换回函数指针就可以了。

  • 我确实认为这就是意图http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195 (2认同)