如果标准容器元素类型和std :: allocator类型不同,这是错误的吗?

时间:2013-07-30 21:04:18

标签: c++

here(这是相当古老的)获取:

  

用于分配器模板的类型也很重要   参数和在标准中用作元素类型的类型   容器同意。例如:

std::list<int, std::allocator<long> >                    // Wrong!
     

无效。

问题

上述陈述是否正确(或是否正确)?无论我在T std::allocator放置什么,我所做的任何测试似乎都能正常工作。例如,std::vector<int, std::allocator<std::string>>已编译并正常工作,推回和删除元素等。 (根据我的理解std::allocator<std::string>::rebind<int>::other是使这项工作变得神奇的原因。)

2 个答案:

答案 0 :(得分:7)

我在这里添加一个答案,以澄清不良行为和未定义行为之间的区别。

[intro.compliance] / P1:

  

可诊断规则集包含所有语法和语义   本国际标准中的规则除了包含的规则   一个明确的符号“不需要诊断”或哪些是   被描述为导致“未定义的行为”。

[defns.ill.formed]:

  

程序不完善

[defns.well.formed]

  

根据语法规则构建的C ++程序,可诊断   语义规则和一个定义规则(3.2)。

在英语中:不正确的程序应具有与之相关的诊断。未定义的行为可以做任何事情:

  1. 它可以按照您的意图编译和执行。
  2. 它可以发出诊断信息。
  3. 它可以删除您编写的代码。
  4. 它可以重新格式化最近的磁盘。
  5. (除了第4次以外通常都会在实践中发生)

    未定义的行为非常糟糕,而imho,C和C ++标准过于宽泛地应用了该规范。

    从技术上讲,违反 Requires 子句会导致未定义的行为。

    [res.on.required] / P1:

      

    违反函数中指定的前提条件要求:   段落导致未定义的行为,除非函数的抛出:   段落指定在前置条件为时抛出异常   侵犯。

    正如MSN所述,allocator_type::value_type应与{99}中的container::value_type相同,如表99所示 - 分配器感知容器要求

    allocator_type A       Requires:  allocator_type::value_type 
                                      is the same as X::value_type.
    

    X表示使用类型为value_type的分配器的T A的分配器感知容器类

    因此违规行为如下:

    std::list<int, std::allocator<long> >  
    

    是未定义的行为。所以它:

    1. 可以按照您的意图编译和执行。
    2. 可以发出诊断信息。
    3. 可以删除您编写的代码。
    4. 可以重新格式化最近的磁盘。
    5. 就在最近(在我写这篇文章的几周内),libc ++(http://libcxx.llvm.org)已经开始用static_assert诊断这个未定义的行为,以便你尽快得到坏消息。

      我们决定采用这个方向,而不是允许行为,因为容器未设置为允许密切相关类型之间的转换。例如:

      std::list<int, std::allocator<long>>  list1;
      std::list<int>                        list2 = list1;  // is specified to not work
      

      即。如果您开始将list1list2视为等效类型,因为无论如何std::allocator获得rebind'd',当您发现这两个时,您将会感到失望列表实际上是不同的类型,并且无论如何都不能设计为互操作。因此,最好尽快得到坏消息,而不是在2个月或2年之后,当你尝试将它们用作等效类型时。

      未来的标准可能会将list1list2视为等效类型。这在技术上是可行的(std::is_same可能不起作用)。但是我没有听到过这方面的建议。这个方向对我来说似乎不太可能。使用static_assert,错误很容易被诊断出来。相反,我希望看到标准的方向是使这个代码形成错误而不是未定义。这样做最困难的部分是对标准进行拼写,而不是在std :: lib实现中。

答案 1 :(得分:6)

编辑:在[containers.requirements.general]中,可识别分配器的容器要求表明allocator_type::value_typeContainer::value_type相同。

因此,虽然至少有一个实现仅使用value_type来获取正确的分配器,但是它传入一个具有不同allocator_traits<...>::rebind<value_type>的分配器类型是不合适的。