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 违规。
instance
在 asio/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
似乎是一个有效的解决方法。但这仍然很难看。
- 是否可以按预期比较 dll 之间的错误(重载
operator==
)?
- 仅
errorCode.value()
与枚举进行比较是正常的还是预期的?
这就是我的意思comment
though boost::system::system_error could invite issues back
问题是,错误类别是全局单例实例,具有 object 身份(即通过地址比较是否相等)。
您将在多个模块中获得多个实例。通常的解决方案是
- 动态 link 到 Boost System,因此所有库都使用相同的副本(但这有时会 运行 进入初始化顺序问题)
- 如果这不能解决问题,请确保所有模块实际加载相同的库(版本?)
- 在最近的提升中,我认为可以选择完全构建提升系统 header-only。这可能涉及也可能不涉及 new-fangled C++14 内联,我没有检查过。
如果一切都失败了,请自己翻译。相关问题可能会给您一些想法:
- Is it possible to convert a boost::system::error_code to a std:error_code?
- 请注意,由于 RTTI 不一定匹配,异常可能 运行 成为非常相似的问题;异常需要导出类型并从同一模块动态 linked,以便异常处理程序匹配抛出的 运行time 类型 ID。
Is it normal or expected to compare only errorCode.value() against enums?
不,不是。根据一些消息来源,Boost 以及标准库承诺将一般错误类别映射到标准的 errc
- 所以你可以这样做,但你仍然必须弄清楚这是否是类别,所以没有帮助你的场景。
我在处理从另一个 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 违规。
instance
在 asio/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
似乎是一个有效的解决方法。但这仍然很难看。
- 是否可以按预期比较 dll 之间的错误(重载
operator==
)? - 仅
errorCode.value()
与枚举进行比较是正常的还是预期的?
这就是我的意思comment
though boost::system::system_error could invite issues back
问题是,错误类别是全局单例实例,具有 object 身份(即通过地址比较是否相等)。
您将在多个模块中获得多个实例。通常的解决方案是
- 动态 link 到 Boost System,因此所有库都使用相同的副本(但这有时会 运行 进入初始化顺序问题)
- 如果这不能解决问题,请确保所有模块实际加载相同的库(版本?)
- 在最近的提升中,我认为可以选择完全构建提升系统 header-only。这可能涉及也可能不涉及 new-fangled C++14 内联,我没有检查过。
如果一切都失败了,请自己翻译。相关问题可能会给您一些想法:
- Is it possible to convert a boost::system::error_code to a std:error_code?
- 请注意,由于 RTTI 不一定匹配,异常可能 运行 成为非常相似的问题;异常需要导出类型并从同一模块动态 linked,以便异常处理程序匹配抛出的 运行time 类型 ID。
Is it normal or expected to compare only errorCode.value() against enums?
不,不是。根据一些消息来源,Boost 以及标准库承诺将一般错误类别映射到标准的 errc
- 所以你可以这样做,但你仍然必须弄清楚这是否是类别,所以没有帮助你的场景。