On 01/14/18 19:30, Peter Dimov via Boost wrote:
Niall Douglas wrote:
If you link all your DLLs with the static MSVC runtime so each gets a copy of a system_category implementation, _Immortalize still ensures that only one instance ever appears to exist in the process. So each error category always gets its unique address in the process. At least, this is what I've been told.
This was an interesting claim so I looked into it.
No, categories from DLLs using the static runtime do not have the same address, and _Immortalize doesn't help with that.
C:\Projects\test_system_error>bin\msvc-14.1\debug\runtime-link-static\single_instance_test.exe
e1: 'system:0'; { 0, 560F6B00 } e2: 'system:0'; { 0, 57E86B00 } No errors detected.
They do, however, compare equal.
The equality comparison simply makes sure that all system categories compare equal:
bool operator==(const error_category& _Right) const _NOEXCEPT { // compare categories for equality return (_Addr == _Right._Addr); }
where
/* constexpr */ error_category() _NOEXCEPT // TRANSITION { // default constructor _Addr = reinterpret_cast
(this); } but
protected: uintptr_t _Addr;
enum : uintptr_t { // imaginary addresses for Standard error_category objects _Future_addr = 1, _Generic_addr = 3, _Iostream_addr = 5, _System_addr = 7 };
Perhaps we need to do something similar in Boost.System; the combination of link=static and runtime-link=shared is disallowed at Boost Jamroot level, but it could still help the "header-only in DLLs" case.
Interesting. It seems to contradict the definition of the `error_category::operator==` in the standard ([syserr.errcat.nonvirtuals]/2), which says it should compare `this` and `&rhs`. This is also reinforced by the note in [syserr.errcat.overview]/1. This enforced implementation seems unnecessary, though. We should probably consider changing it, either by marking it a defect or filing a proposal.