10

这里取(这很旧):

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

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

不会工作。

问题

上述陈述是否正确(或者曾经正确)?无论我Tstd::allocator. 例如,std::vector<int, std::allocator<std::string>>编译和工作正常推回和擦除元素等(据我了解std::allocator<std::string>::rebind<int>::other是使这项工作的魔力)。

4

2 回答 2

7

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

[intro.compliance]/p1:

可诊断规则集由本国际标准中的所有句法和语义规则组成,但那些包含“不需要诊断”的明确表示法或被描述为导致“未定义行为”的规则除外。</p>

[defns.ill.formed]:

格式不正确的程序

[defns.well.formed]

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

用英语:一个格式错误的程序应该有一个与之相关的诊断。未定义的行为可以做任何事情:

  1. 它可以按照您的意图编译和执行。
  2. 它可以发出诊断。
  3. 它可以删除您编写的代码。
  4. 它可以重新格式化最近的磁盘。

(除了第 4 次以外的所有情况在实践中都经常发生)

未定义的行为非常糟糕,恕我直言,C 和 C++ 标准过于宽松地应用了该规范。

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

[res.on.required]/p1:

违反函数的 Requires: 段落中指定的先决条件会导致未定义的行为,除非函数的 Throws: 段落指定在违反先决条件时引发异常。

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

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

X表示一个可感知分配器的容器类,其中一个使用类型value_type为 的分配器)TA

所以违规如:

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

是未定义的行为。所以:

  1. 可以按照您的意图编译和执行。
  2. 可以发出诊断。
  3. 可以删除你写的代码。
  4. 可以重新格式化最近的磁盘。

就在最近(在我写这篇文章的几周内),libc++(http://libcxx.llvm.org)已经开始诊断这种未定义的行为,static_assert以便您尽快得到坏消息。

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

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

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

也许未来的标准会将list1list2视为等效类型。这在技术上大多是可行的(std::is_same可能行不通)。但是我没有听说过这方面的建议。这个方向在我看来不太可能。并且static_assert,错误很容易诊断。相反,我希望看到标准朝着使此代码格式错误而不是未定义的方向发展。这样做最困难的部分是对标准进行文字锻造,而不是在 std::lib 实现中。

于 2013-07-31T03:24:18.303 回答
6

allocator_type::value_type编辑:在 [containers.requirements.general]中,分配器感知容器要求表明Container::value_type.

value_type因此,尽管至少有一个实现只是简单地用于allocator_traits<...>::rebind<value_type>获取正确的分配器,但传入具有不同 的分配器类型是不正确的。

于 2013-07-30T22:00:34.957 回答