error_category 跨 dll 使用时 asio 不匹配

error_category mismatch in asio when used across dlls

我在处理从另一个 dll 或可执行文件接收到的 asio::error_code 值时遇到问题。例如,我可能 运行 一个带有处理程序的异步操作:

socket.async_receive([](const asio::error_code& errorCode)
{
    if (errorCode == asio::error::operation_aborted)
       return;
}

如果处理程序是在 dll 中创建的,并且 errorCode 是从另一个 dll 或可执行文件传递的,operator== 将 return 为假,因为它们的 error_category 值不同。例如:

(gdb) info sym 0x55f1c0
asio::system_category()::instance in section .data of C:\dev\builds\UWCASdk\Debug-MinGW-w64\Sandbox\ServerL410F\bin\sb.ServerL410F.exe
(gdb) info sym 0x6f0420d0
asio::system_category()::instance in section .data of C:\dev\builds\UWCASdk\Debug-MinGW-w64\Sandbox\ServerL410F\bin\libproviders.protobuf.client_d.dll

很明显,这两个实例是在不同的单元中定义的,我基本上有 ODR 违规。

instanceasio/impl/error_code.ipp:

中定义
const error_category& system_category()
{
  static detail::system_category instance;
  return instance;
}

ASIO 文档在处理错误时没有提及任何关于 error_cateegory 的内容——它只指定了枚举值,因此使用 errorCode.value == asio::error::operation_aborted 似乎是一个有效的解决方法。但这仍然很难看。

这就是我的意思comment

though boost::system::system_error could invite issues back

问题是,错误类别是全局单例实例,具有 object 身份(即通过地址比较是否相等)。

您将在多个模块中获得多个实例。通常的解决方案是

  • 动态 link 到 Boost System,因此所有库都使用相同的副本(但这有时会 运行 进入初始化顺序问题)
  • 如果这不能解决问题,请确保所有模块实际加载相同的库(版本?)
  • 在最近的提升中,我认为可以选择完全构建提升系统 header-only。这可能涉及也可能不涉及 new-fangled C++14 内联,我没有检查过。

如果一切都失败了,请自己翻译。相关问题可能会给您一些想法:


Is it normal or expected to compare only errorCode.value() against enums?

不,不是。根据一些消息来源,Boost 以及标准库承诺将一般错误类别映射到标准的 errc - 所以你可以这样做,但你仍然必须弄清楚这是否是类别,所以没有帮助你的场景。