为什么libc++';s的map实现是否使用此联合? #如果uu cplusplus>=201103L 模板 并集值类型 { typedef_Key_type; typedef _tpmapped_type; typedef对值_类型; typedef对uu nc_值u类型; 值\类型\ cc; __nc\值\类型\ nc; 模板 _LIBCPP_内联_可见性 __值类型(_参数&&…_参数) :_cc(std::forward(_args)…{} _LIBCPP_内联_可见性 __值类型(常数值类型&) :uu cc(u v.u cc){} _LIBCPP_内联_可见性 __值类型(\uuuu值类型和\uu v) :uu cc(u v.u cc){} _LIBCPP_内联_可见性 __值类型(值类型&&v) :uu nc(std::move(u v.u nc)){ _LIBCPP_内联_可见性 __值类型和运算符=(常量值类型和运算符) {{uuuu nc=\uuu v.\uu cc;返回*this;} _LIBCPP_内联_可见性 __值类型和运算符=(\uu值类型和&uu v) {uuuu nc=std::move(uu v.uu nc);返回*this;} _LIBCPP_内联_可见性 ~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\} }; #否则 //C++03的定义。。。

为什么libc++';s的map实现是否使用此联合? #如果uu cplusplus>=201103L 模板 并集值类型 { typedef_Key_type; typedef _tpmapped_type; typedef对值_类型; typedef对uu nc_值u类型; 值\类型\ cc; __nc\值\类型\ nc; 模板 _LIBCPP_内联_可见性 __值类型(_参数&&…_参数) :_cc(std::forward(_args)…{} _LIBCPP_内联_可见性 __值类型(常数值类型&) :uu cc(u v.u cc){} _LIBCPP_内联_可见性 __值类型(\uuuu值类型和\uu v) :uu cc(u v.u cc){} _LIBCPP_内联_可见性 __值类型(值类型&&v) :uu nc(std::move(u v.u nc)){ _LIBCPP_内联_可见性 __值类型和运算符=(常量值类型和运算符) {{uuuu nc=\uuu v.\uu cc;返回*this;} _LIBCPP_内联_可见性 __值类型和运算符=(\uu值类型和&uu v) {uuuu nc=std::move(uu v.uu nc);返回*this;} _LIBCPP_内联_可见性 ~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\} }; #否则 //C++03的定义。。。,c++,c++11,dictionary,stl,libc++,C++,C++11,Dictionary,Stl,Libc++,其目的似乎是使\uuu value\u type可分配和可移动,同时还能够将内容公开为对(这是迭代器的值类型等)。但是我不明白为什么它需要是可分配的或可移动的,因为我不明白为什么实现需要在映射中复制或移动节点,或者除了在适当的位置构造和销毁节点以及重新配置指针之外,还需要做任何事。当您使用自定义分配器时,可能需要移动映射(及其内容)放入新的资源池。在这种情况下,此重载将提供对密钥的移动访问: #if __cplusplus >= 201103L template <class _K

其目的似乎是使
\uuu value\u type
可分配和可移动,同时还能够将内容公开为
对(这是迭代器的值类型等)。但是我不明白为什么它需要是可分配的或可移动的,因为我不明白为什么实现需要在映射中复制或移动节点,或者除了在适当的位置构造和销毁节点以及重新配置指针之外,还需要做任何事。

当您使用自定义分配器时,可能需要移动映射(及其内容)放入新的资源池。在这种情况下,此重载将提供对密钥的移动访问:

#if __cplusplus >= 201103L

template <class _Key, class _Tp>
union __value_type
{
    typedef _Key                                     key_type;
    typedef _Tp                                      mapped_type;
    typedef pair<const key_type, mapped_type>        value_type;
    typedef pair<key_type, mapped_type>              __nc_value_type;

    value_type __cc;
    __nc_value_type __nc;

    template <class ..._Args>
    _LIBCPP_INLINE_VISIBILITY
    __value_type(_Args&& ...__args)
        : __cc(std::forward<_Args>(__args)...) {}

    _LIBCPP_INLINE_VISIBILITY
    __value_type(const __value_type& __v)
        : __cc(__v.__cc) {}

    _LIBCPP_INLINE_VISIBILITY
    __value_type(__value_type& __v)
        : __cc(__v.__cc) {}

    _LIBCPP_INLINE_VISIBILITY
    __value_type(__value_type&& __v)
        : __nc(std::move(__v.__nc)) {}

    _LIBCPP_INLINE_VISIBILITY
    __value_type& operator=(const __value_type& __v)
        {__nc = __v.__cc; return *this;}

    _LIBCPP_INLINE_VISIBILITY
    __value_type& operator=(__value_type&& __v)
        {__nc = std::move(__v.__nc); return *this;}

    _LIBCPP_INLINE_VISIBILITY
    ~__value_type() {__cc.~value_type();}
};

#else
// definition for C++03...
关键点是否从中移动并不重要,因为接下来发生的事情是释放所有节点

请注意,这种用法可能会导致未定义的行为。通常不能先写入一个联合的成员,然后再读取另一个。Clang和libc++可以这样做,只要它们能够在内部保证不会导致问题(或错误诊断)

不过,他们可能是这样做的,因为没有好的一致性替代方案。至少,我想不出一个。标准要求
value\u-type::first\u-type
确实是
const
合格的,所以即使是
const\u-cast
也不允许

如果
key\u-type
mapped\u-type
都是标准布局,则技巧是一致的,因此
std::pair
std::pair
根据[class.mem]是布局兼容的§9.2/16.这里看起来有点奇怪,因为函数是指联合体的直接成员
\uuuu cc
\uu nc
,让构造函数访问由
第一个
第二个
组成的公共子序列。标准布局类型的规则有些限制,但许多公共键和value类型(例如,
std::string
)可能满足它们的要求。

这是为了支持的答案。我作为这个libc++代码的作者回答

考虑:

__value_type(__value_type&& __v)
    : __nc(std::move(__v.__nc)) {}
对于libstdc++(gcc-5.2.0)

对于VS-2015:

start copy assignment
~A()
A(A const& a)
~A()
A(A const& a)
~A()
A(A const& a)
end copy assignment
我断言,当
A
是一种类型,如
int
std::vector
std::string
,或是一种包含这些常见std类型之一的类型时,与先破坏后构造相比,赋值具有巨大的性能优势。赋值通常可以利用lhs中的现有容量产生一个简单的
memcpy
,而不是先释放内存再分配内存

请注意,上面的
~A()
可能意味着整个节点的解除分配,而不仅仅是
A
(虽然不一定)。在任何情况下,libc++
map
copy assignment操作符都经过了高度优化以回收内存,并且该优化的权限得到了C++11的支持,并且超出了标准。联合技巧就是其中之一(不一定是可移植的)实现优化的方法

当分配器在移动分配时不传播且两个分配器比较不相等时,移动分配运算符的相同代码可获得类似的优化:

clang/libc++:

start copy assignment
~A()
~A()
~A()
A(A const& a)
A(A const& a)
A(A const& a)
end copy assignment
gcc-5.2.0

start copy assignment
operator=(const A& a)
operator=(const A& a)
operator=(const A& a)
end copy assignment
start move assignment
operator=(A&& a)
operator=(A&& a)
operator=(A&& a)
end move assignment
VS-2015

start move assignment
~A()
A(A const& a)
~A()
A(A const& a)
~A()
A(A const& a)
~A()
~A()
~A()
end move assignment

您是否尝试在文件中搜索
\uu nc
的用法?请注意,无论如何,此联合建议的用法都不一致。@Potatoswatter是的,它仅用于实现所显示的成员。这可能是核心语言、库或两者都有缺陷。通常,库应该可以使用该语言实现。是否希望要报告问题?@Potatoswatter实现允许使用“magic”@Mattmcnab标准库的神奇部分主要保留在§18中。委员会的目的是普通类型的数据结构不需要魔法。同样,libc++与Clang是不同的项目,许多其他标准库的目的是至少在某种程度上可移植。这不符合9.2/16 applies仅适用于标准布局结构,
K
V
不一定是标准布局。此外,您只允许读取公共初始序列,但移动通常需要写入。@T.C.-另一方面,标准库实现允许使用其编译器定义良好的结构(作为扩展,可能未记录)。@T.C.谢谢,我恢复了原始段落并进行了修订。我看到的关于阅读和写作的语言是“允许检查”,非常清晰。@T.C.谢谢,我寻找了类似的内容,但没有找到。DR提到“涉及std::pair等的特定用例,”这使得它看起来只是针对这个实现问题量身定做的。如果它没有走得足够远,实际上是很奇怪的
start move assignment
~A()
A(A const& a)
~A()
A(A const& a)
~A()
A(A const& a)
~A()
~A()
~A()
end move assignment
start move assignment
~A()
~A()
~A()
A(A const& a)
A(A const& a)
A(A const& a)
end move assignment