从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
是使这项工作变得神奇的原因。)
答案 0 :(得分:7)
我在这里添加一个答案,以澄清不良行为和未定义行为之间的区别。
[intro.compliance] / P1:
可诊断规则集包含所有语法和语义 本国际标准中的规则除了包含的规则 一个明确的符号“不需要诊断”或哪些是 被描述为导致“未定义的行为”。
[defns.ill.formed]:
程序不完善
[defns.well.formed]
根据语法规则构建的C ++程序,可诊断 语义规则和一个定义规则(3.2)。
在英语中:不正确的程序应具有与之相关的诊断。未定义的行为可以做任何事情:
(除了第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> >
是未定义的行为。所以它:
就在最近(在我写这篇文章的几周内),libc ++(http://libcxx.llvm.org)已经开始用static_assert
诊断这个未定义的行为,以便你尽快得到坏消息。
我们决定采用这个方向,而不是允许行为,因为容器未设置为允许密切相关类型之间的转换。例如:
std::list<int, std::allocator<long>> list1;
std::list<int> list2 = list1; // is specified to not work
即。如果您开始将list1
和list2
视为等效类型,因为无论如何std::allocator
获得rebind
'd',当您发现这两个时,您将会感到失望列表实际上是不同的类型,并且无论如何都不能设计为互操作。因此,最好尽快得到坏消息,而不是在2个月或2年之后,当你尝试将它们用作等效类型时。
未来的标准可能会将list1
和list2
视为等效类型。这在技术上是可行的(std::is_same
可能不起作用)。但是我没有听到过这方面的建议。这个方向对我来说似乎不太可能。使用static_assert
,错误很容易被诊断出来。相反,我希望看到标准的方向是使这个代码形成错误而不是未定义。这样做最困难的部分是对标准进行拼写,而不是在std :: lib实现中。
答案 1 :(得分:6)
编辑:在[containers.requirements.general]中,可识别分配器的容器要求表明allocator_type::value_type
与Container::value_type
相同。
因此,虽然至少有一个实现仅使用value_type
来获取正确的分配器,但是它传入一个具有不同allocator_traits<...>::rebind<value_type>
的分配器类型是不合适的。