一些STL容器的std::allocator不匹配

9

在STL容器的模板参数中,使用不匹配的std::allocator特化(当然,除了针对void的特化)在技术上是否有效?以下代码可以编译通过,但只适用于下列枚举的容器:unordered_(multi)map/set。

#include <list>
#include <forward_list>
#include <deque>
#include <set>
#include <map>

int main()
{
    struct A { bool operator < (A) const { return true; } };
    struct B {};
    struct C {};
    std::list< A, std::allocator< C > > l;
    std::forward_list< A, std::allocator< C > > fl;
    std::deque< A, std::allocator< C > > d;
    std::set< A, std::less< A >, std::allocator< C > > s;
    std::multiset< A, std::less< A >, std::allocator< C > > ms;
    std::map< A, B, std::less< A >, std::allocator< C > > m;
    std::multimap< A, B, std::less< A >, std::allocator< C > > mm;
}

我认为这是由于分配器立即重新绑定到底层节点类型而与其源类型无关。

我会说这可能是未定义行为,但我不确定(也许分配器对于不同类型来说是相同的)。 - Paul Stelian
1个回答

10
我认为这在C++11中是UB(至少在C++11中),因为指定一个分配器,其value_type与容器的value_type不同,违反了分配器感知容器要求,这意味着这些实例不符合一般容器要求。此外,我找不到C++11标准中任何关于分配器类型必须从提供的模板参数类型重新绑定的规定。

1. [container.requirements.general]部分告诉我们:

13)除了数组之外,在本条款和(21.4)中定义的所有容器都满足分配器感知容器的附加要求,如表99所述。

2. 分配器感知容器要求如下:

要求:allocator_type::value_typeX::value_type相同。

  1. [default.allocator]部分指定

typedef T value_type;

作为命名空间stdallocator模板的成员。

4. [multimap.overview]部分包含:

template <class Key, class T, class Compare = less<Key>,
    class Allocator = allocator<pair<const Key, T> > >
class multimap {
    [...]
    typedef Allocator allocator_type;
    [...]
 };

(对于其他容器也有类似的发现。)

1
@orient: 不会,因为第4点中的typedef可能会读取类似于typedef typename std :: allocator_traits <Allocator> :: template rebind_alloc <value_type> allocator_type;这样的内容,这将使情况有所不同。 - Pixelchemist
3
附加信息:libc++通过static_assert在编译时捕获此未定义行为。 - Howard Hinnant
1
附加信息:libstdc++故意不捕获此错误,因为我们支持它作为符合性扩展,但我一直想在不需要扩展时添加静态断言以进行严格模式。 - Jonathan Wakely
@Pixelchemist,我甚至不确定我是否理解了你的问题。std::list<T, A>的内部节点类型应该分配什么样的value_type才是正确的呢?肯定不是A,因为它只为T类型的对象分配内存。std::deque<T, A>分配指向其页面的指针表时,应该分配什么样的value_type才是正确的呢?也不是A。也许你应该考虑当容器要求"allocator_type::value_typeX::value_type相同"时,如何提供具有适当value_type的分配器。它们必须重新绑定。 - Jonathan Wakely
@Pixelchemist,我特别说了basic_stringvector不需要重新绑定 :-) 所以_"为什么要重新绑定一个具有正确value_type的分配器?"_你不需要。但通常它具有错误的value_type,所以你需要重新绑定。 - Jonathan Wakely
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接