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_mapis an allocator-aware container, and the assignment operation of allocator-aware containers requires that thevalue_typebe copy assignable - seecontainers.allocatoraware- and thenunord.reqsays that for the purposes of requirements in the unordered containers, one looks tokey_typeandmapped_typeinstead.This happened to work in previous releases of Visual C++ because
std::list, out of whichstd::unordered_mapis 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_mapsatisfies 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