gpt4 book ai didi

c++ - std::any 跨越 mingw 中的共享库边界

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:42:45 29 4
gpt4 key购买 nike

我在跨共享库边界使用 libstdc++ 的 std::any 实现和 mingw 时偶然发现了一个问题。它会产生一个 std::bad_any_cast 显然不应该(我相信)。

我使用 mingw-w64、gcc-7 并使用 -std=c++1z 编译代码。

简化代码:

main.cpp :

#include <any>
#include <string>

// prototype from lib.cpp
void do_stuff_with_any(const std::any& obj);

int main()
{
do_stuff_with_any(std::string{"Hello World"});
}

lib.cpp:

将被编译成共享库并与 main.cpp 中的可执行文件链接。

#include <any>
#include <iostream>

void do_stuff_with_any(const std::any& obj)
{
std::cout << std::any_cast<const std::string&>(obj) << "\n";
}

虽然传递给 do_stuff_with_any 的 any 确实包含一个字符串,但这会触发 std::bad_any_cast。我深入研究了 gcc 的 any 实现,它似乎使用比较静态内联成员函数(根据存储对象的类型从模板结构中选择的管理器)的地址来检查 any 是否包含请求类型的对象.而且这个函数的地址似乎跨共享库边界发生了变化。

难道 std::any 不能保证跨共享库边界工作吗?此代码会在某处触发 UB 吗?或者这是 gcc 实现中的错误?我很确定它可以在 linux 上运行,所以这只是 mingw 中的一个错误吗?它是已知的还是我应该在某个地方报告它?有任何(临时)解决方法的想法吗?

最佳答案

虽然这确实是 Windows DLL 如何工作的问题,并且从 GCC 8.2.0 开始,问题仍然存在,但可以通过将 any header 中的 __any_caster 函数更改为以下内容来轻松解决此问题:

template<typename _Tp>
void* __any_caster(const any* __any)
{
if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
{
#if __cpp_rtti
if (__any->type().hash_code() == typeid(_Tp).hash_code())
#else
if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
#endif
{
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
}
return nullptr;
}

或类似的东西,唯一相关的部分是包裹在#if 中的比较行。

详细来说,管理器函数有两个拷贝,一个在 exe 上,一个在 dll 上,传递的对象包含 exe 的地址,因为这是它创建的地方,但是一旦它到达 dll 端,指针与 dll 地址空间中的地址空间进行比较,后者永远不会匹配,因此,应该比较类型信息 hash_codes。

关于c++ - std::any 跨越 mingw 中的共享库边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45290296/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com