struct const_int { const int x = 1; };
int main(int argc, char **argv)
{
std::unordered_map<int, const_int> map0;
std::unordered_map<int, const_int> map1 { map0 }; // OK
map1 = map0; // Compile-time error
return 0;
}
This code works in Visual C++ 2017, but fails with compile error in Visual C++ 2019:
14.23.27911\include\list(1210): error C2280: 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)': attempting to reference a deleted function
with
[
_Kty=int,
_Ty=const_int
]
Which compiler version has correct implementation, or behavior is not defined in this case?
Quoting Billy Robert O'Neil III from visual studio developer community this is not a bug:
This is not a bug.
unordered_map
is an allocator-aware container, and the assignment operation of allocator-aware containers requires that thevalue_type
be copy assignable - seecontainers.allocatoraware
- and thenunord.req
says that for the purposes of requirements in the unordered containers, one looks tokey_type
andmapped_type
instead.This happened to work in previous releases of Visual C++ because
std::list
, out of whichstd::unordered_map
is constructed, used to deallocate all nodes during an assignment operation, so even though it was permitted to assign elements, we happened not to. But that meant that assigning 100 values into a list already containing 100 elements would do 200 unnecessary calls to the allocator: deallocating all 100 old nodes, then allocating 100 new nodes. The behavior change you observe is because in VS2019 Update 2, we implemented an optimization to reuse already-allocated nodes in an assignment.
In addition to @MofX's answer I'd like to add some resources here, also because the quoted text contains invalid links.
From [unord.map]/2 (emphasis mine):
An
unordered_map
satisfies all of the requirements of a container, of an unordered associative container, and of an allocator-aware container.
This leads to [container.requirements.general]/16, where for the assignment expression in Table 86 the requirements are (emphasis mine):
Requires: T is CopyInsertable into X and CopyAssignable.
Of course, the type used in the OP's example struct const_int { const int x = 1; };
is not copy assignable (due to the const
and no user-defined assignment operator) and therefore the compilation fails.
I hope this makes it clearer.
(Disclaimer: Initially I was convinced MSVC has a bug here but I was proven wrong)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With