nyo*_*ain 5 c++ mingw std shared-libraries c++17
当在共享库边界上使用libstdc ++的std :: any mingw实现时,我偶然发现了一个问题。它产生一个std::bad_any_cast明显不应该(我相信)的地方。
我使用mingw-w64,gcc-7并使用-std = c ++ 1z编译代码。
简化代码:
#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"});
}
Run Code Online (Sandbox Code Playgroud)
将被编译到一个共享库中,并与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";
}
Run Code Online (Sandbox Code Playgroud)
尽管任何传递到的do_stuff_with_any都包含字符串,但这会触发std :: bad_any_cast 。我深入研究了gcc的any实现,它似乎使用了静态内联成员函数(根据所存储对象的类型从模板结构中选择的管理器)的地址进行比较,以检查是否包含所请求类型的对象。而且此函数的地址似乎在共享库的边界上发生了变化。
是不是std :: any不能跨共享库边界工作?该代码是否在某处触发UB?还是这是gcc实施中的错误?我很确定它可以在linux上运行,所以这只是mingw中的错误吗?是已知的还是应该在某个地方报告?对(临时)解决方法有什么想法吗?
虽然这是一个关于 Windows DLL 如何工作的问题,并且从 GCC 8.2.0 开始,这个问题仍然存在,但可以通过将 any 标头内的 __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;
}
Run Code Online (Sandbox Code Playgroud)
或者类似的东西,唯一相关的部分是#if 中包含的比较行。
详细来说,管理器函数有 2 个副本,一个在 exe 上,一个在 dll 上,传递的对象包含 exe 的地址,因为那是它的创建位置,但是一旦它到达 dll 端,指针就会与dll 地址空间中的地址永远不会匹配,因此应该比较类型 info hash_codes。
| 归档时间: |
|
| 查看次数: |
400 次 |
| 最近记录: |