如果元素不可分配,则复制分配地图

ran*_*dom 16 c++

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;
}
Run Code Online (Sandbox Code Playgroud)

该代码在Visual C ++ 2017中有效,但在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
            ]
Run Code Online (Sandbox Code Playgroud)

哪个编译器版本具有正确的实现,或者在这种情况下未定义行为?

Mof*_*ofX 17

从Visual Studio开发人员社区引用Billy Robert O'Neil III,这不是错误:

这不是错误。unordered_map是一个可识别分配器的容器,并且可识别分配器的容器的分配操作需要是value_type可复制分配的(请参阅containers.allocatoraware),然后unord.req说,出于对无序容器中的需求的目的,请查看key_typemapped_type代替。

这恰好在Visual C ++的早期版本中起作用,因为在赋值操作期间构造std::list了其中的std::unordered_map一个结构,用于释放所有节点,因此即使允许分配元素,我们也没有这样做。但这意味着向已经包含100个元素的列表中分配100个值将对分配器进行200次不必要的调用:释放所有100个旧节点,然后分配100个新节点。您观察到的行为更改是因为在VS2019 Update 2中,我们实现了优化以重用分配中已分配的节点。


and*_*eee 5

除了@MofX的答案外,我还要在此处添加一些资源,这也是因为引用的文本包含无效链接。

[unord.map] / 2(强调我的):

一个unordered_­map满足所有的容器的需求的无序关联容器,和的分配感知 容器。

这导致[container.requirements.general] / 16,对于表86中的赋值表达式,要求是(强调我的):

要求:T是CopyInsertable到X和CopyAssignable

当然,在OP的例子中使用的类型struct const_int { const int x = 1; };复制分配(由于const和没有用户定义的赋值运算符),因此编译失败。

我希望这可以使它更清楚。

(免责声明:最初,我确信MSVC在此处存在错误,但事实证明我错了)

  • 您可以将其编辑为我的答案。 (2认同)