【问题标题】:Returning unique_ptr from a function executed via dlsym从通过 dlsym 执行的函数返回 unique_ptr
【发布时间】:2025-12-16 17:15:02
【问题描述】:

我有一个位于共享对象中的函数,它从主程序中使用dlsym 加载和执行。 (共享对象和主程序都是C++)

这个函数会不会返回std::unique_ptr

共享对象函数 -

extern "C" {
    unique_ptr<Obj> some_function() {
        return make_unique<Obj>();
    }
}

主程序:

void main_flow() {
    auto handle = dlopen(...);
    FuncPtr func = dlsym(handle, "some_function");
    unique_ptr<Obj> func();
}

【问题讨论】:

  • extern C 只是禁用 C++ 名称修改。在具有 C 命名约定的 func 中使用唯一指针没有问题。

标签: c++ unique-ptr dlsym extern-c


【解决方案1】:

是的,有很多警告。首先,在 DSO 接口中使用 boost 或 STL 有点危险。

  1. std::unique_ptr 因编译器而异
  2. std::unique_ptr 在 C++ 版本之间有所不同
  3. std::unique_ptr 可能在调试/发布版本之间有所不同。

这意味着,如果您在 DSO 接口中使用 STL 或 boost,所有 exe 和 dsos 必须使用完全相同版本的 C++ 运行时编译,并使用相同的构建标志(如果您喜欢,则使用相同版本的 boost)。

我建议在 Visual Studio 上使用警告级别 4,它可以很好地列出 DSO 界面中的所有上述问题(作为 C4251 警告)

至于您的问题,是的,该函数将返回 std::unique_ptr,但是您现在正在 DSO 中分配内存,您可能正在 exe 中释放这些内存。这在 Windows 世界中可能非常糟糕,您可能会发现调试版本具有不同的堆。尝试在 EXE 堆中释放 DSO 分配的对象将引发运行时错误,但通常仅在调试版本中。

你的 main 应该是这样的:

void main_flow() {
  auto handle = dlopen(...);
  FuncPtr func = (FuncPtr)dlsym(handle, "some_function");
  unique_ptr<Obj> obj = func();
}  

不过,我个人建议只返回一个裸指针,并在您的 exe 中对其执行 make_unique。这至少消除了 C4251 问题,尽管您可能会被堆问题所困扰(除非您将类类型的析构函数设为虚拟)

【讨论】: