简体   繁体   English

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

[英]Is it wrong if the standard container element type and std::allocator type are different?

Take from here (which is quite old): 这里开始 (这是相当古老的):

It's also important that the type used for the allocator template parameter and the type used as the element type in a standard container agree. 用于allocator模板参数的类型和用作标准容器中的元素类型的类型一致也很重要。 For instance: 例如:

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

won't work. 不行。

Question

Is the above statement correct (or was it ever correct)? 以上陈述是否正确(或者是否正确)? Any tests I have done seem to work fine no matter what I put for T in std::allocator . 无论我在std::allocatorT做什么,我所做的任何测试似乎都能正常工作。 For example, std::vector<int, std::allocator<std::string>> compiled and worked fine pushing back and erasing elements, etc. (From what I understand std::allocator<std::string>::rebind<int>::other is the magic that makes this work). 例如, std::vector<int, std::allocator<std::string>>编译并正常工作推回和擦除元素等(根据我的理解std::allocator<std::string>::rebind<int>::other是使这项工作变得神奇的魔力。

I'm adding an answer here to clarify the difference between ill-formed and undefined behavior. 我在这里添加一个答案,以澄清不良行为和未定义行为之间的区别。

[intro.compliance]/p1: [intro.compliance] / P1:

The set of diagnosable rules consists of all syntactic and semantic rules in this International Standard except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “undefined behavior.” 可诊断规则集包含本国际标准中的所有语法规则和语义规则,但那些包含“无需诊断”的明确表示法或被描述为导致“未定义行为”的规则除外。

[defns.ill.formed]: [defns.ill.formed]:

program that is not well formed 程序不完善

[defns.well.formed] [defns.well.formed]

C++ program constructed according to the syntax rules, diagnosable semantic rules, and the One Definition Rule (3.2). C ++程序根据语法规则,可诊断语义规则和单定义规则(3.2)构建。

In English: an ill-formed program shall have a diagnostic associated with it. 在英语中:不正确的程序应具有与之相关的诊断。 Undefined behavior can do anything: 未定义的行为可以做任何事情:

  1. It can compile and execute as you intended. 它可以按照您的意图编译和执行。
  2. It can issue a diagnostic. 它可以发出诊断。
  3. It can delete the code you have written. 它可以删除您编写的代码。
  4. It can reformat the nearest disk. 它可以重新格式化最近的磁盘。

(all but the 4th routinely happen in practice) (除了第4次以外通常都会在实践中发生)

Undefined behavior is very bad, and imho, the C and C++ standards apply that specification much too liberally. 未定义的行为非常糟糕,而imho,C和C ++标准过于宽松地应用了该规范。

Technically, violating a Requires clause results in undefined behavior. 从技术上讲,违反Requires子句会导致未定义的行为。

[res.on.required]/p1: [res.on.required] / P1:

Violation of the preconditions specified in a function's Requires: paragraph results in undefined behavior unless the function's Throws: paragraph specifies throwing an exception when the precondition is violated. 违反函数的Requires:段中指定的前提条件会导致未定义的行为,除非函数的Throws:paragraph指定在违反前提条件时抛出异常。

As noted by MSN, allocator_type::value_type shall be the same as container::value_type as stated in Table 99 -- Allocator-aware container requirements . 如MSN所述, allocator_type::value_type应与表99中所述的container::value_type相同 - 可识别分配器的容器要求

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

( X denotes an allocator-aware container class with a value_type of T using allocator of type A ) X表示一个分配器感知容器类,其value_typeT使用类型A分配器)

So a violation such as: 所以违反如下:

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

is undefined behavior. 是未定义的行为。 So it: 所以:

  1. can compile and execute as you intended. 可以按照您的意图编译和执行。
  2. can issue a diagnostic. 可以发出诊断。
  3. can delete the code you have written. 可以删除您编写的代码。
  4. can reformat the nearest disk. 可以重新格式化最近的磁盘。

Just very recently (within weeks of me writing this), libc++ ( http://libcxx.llvm.org ) has started diagnosing this undefined behavior with static_assert so that you get the bad news asap. 就在最近(在我写这篇文章的几周内),libc ++( http://libcxx.llvm.org )已经开始用static_assert诊断这个未定义的行为,以便你尽快得到坏消息。

We decided to go this direction, instead of allowing the behavior because the containers are not set up to allow conversions among closely related types. 我们决定采用这个方向,而不是允许行为,因为容器没有设置为允许密切相关类型之间的转换。 For example: 例如:

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

Ie if you start treating list1 and list2 as equivalent types because the std::allocator gets rebind 'd anyway, you're going to get disappointed down the road as you discover the two lists are really different types and not designed to interoperate anyway. 即如果你开始将list1list2视为等效类型,因为std::allocator无论如何都会rebind ,当你发现这两个列表实际上是不同的类型并且无论如何都不能进行互操作时,你会感到很失望。 So it is really best to get the bad news asap, instead of finding out 2 months, or 2 years later, when you try to use them as equivalent types. 所以最好尽快得到坏消息,而不是在2个月或2年之后发现,当你尝试将它们用作等效类型时。

Perhaps a future standard will treat list1 and list2 as equivalent types. 也许未来的标准会将list1list2视为等效类型。 It is mostly technically possible ( std::is_same would likely not work). 它在技术上大多数可能( std::is_same可能不起作用)。 But there are no proposals that I've heard of in this direction. 但是我没有听到过这方面的建议。 This direction does not seem likely to me. 这个方向对我来说似乎不太可能。 And with static_assert , the error is easily diagnosable. 使用static_assert ,错误很容易被诊断出来。 Instead I would like to see the standard move in the direction of making this code ill-formed instead of undefined. 相反,我希望看到标准的方向是使这个代码形成错误而不是未定义。 The hardest part in doing so would be word-smithing the standard, and not in the std::lib implementation. 这样做最困难的部分是字标准,而不是std :: lib实现。

EDIT: In [containers.requirements.general], the Allocator-aware container requirements indicate that the allocator_type::value_type is the same as Container::value_type . 编辑:在[containers.requirements.general]中,Allocator感知容器要求表明allocator_type::value_typeContainer::value_type相同。

So it's ill formed to pass in an allocator type with a different value_type , although at least one implementation simply uses allocator_traits<...>::rebind<value_type> to get the correct allocator. 因此,传入具有不同value_type的allocator类型是value_type ,尽管至少有一个实现只使用allocator_traits<...>::rebind<value_type>来获取正确的分配器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么std :: allocator :: construct和std :: allocator :: destroy模板化元素类型? - Why are std::allocator::construct and std::allocator::destroy templated on element type? 对于具有默认分配器的标准容器,std :: container :: size_type是否保证为size_t? - Is std::container::size_type guaranteed to be size_t for standard containers with default allocator? 为什么标准容器需要allocator_type :: value_type作为元素类型? - Why do standard containers require allocator_type::value_type to be the element type? 没有从“ std :: allocator”到“ const allocator_type”的转换 - no conversion from “std::allocator” to “const allocator_type” 为什么编译器允许使用与使用的容器不同的值类型的分配器 - Why do compilers allow an allocator of a different value type than the container used std :: queue具有不同的容器类型,具体取决于运行时数据 - std::queue with different container type depending on runtime data std :: map是按引用,按值分配分配器还是将其纯粹用作类型? - Does a std::map take an allocator by reference, by value or use it purely as a type? 使用自定义分配器分配std :: vector并在运行时键入unknown - Allocating a std::vector with custom allocator and type unknown at runtime 如何解析像std :: allocator_traits这样的可选嵌套类型? - How to resolve optional nested type like std::allocator_traits? 为什么 std::list 可以有一个 T 类型的分配器? - Why can std::list have an allocator of type T?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM