12

STL 容器要求存储的值是可复制构造和可分配的。const T 显然不是任何 T 的可分配类型,但我尝试使用它(只是好奇)并发现它可以编译,而且,它表现为可分配类型。

vector<const int> v(1);
v[0] = 17;

这在 Visual Studio 2008 中成功运行并将 v[0] 分配给 17。

4

2 回答 2

12

正如其他人所建议的那样,这不是实施中的错误。

违反 C++ 标准库设施的要求不会使您的程序格式错误,它会产生未定义的行为。

您违反了存储在容器中的值类型必须是可复制构造和可分配的要求(const显然,类型不可分配),因此您的程序表现出未定义的行为。

C++ 标准中适用的语言可以在 C++03 17.4.3.6 [lib.res.on.functions] 中找到:

在某些情况下(替换函数、处理函数、对用于实例化标准库模板组件的类型的操作),C++ 标准库依赖于 C++ 程序提供的组件。如果这些组件不满足其要求,则标准对实施没有要求。

特别是,在以下情况下效果是不确定的:

...

  • 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作未实现适用的要求子条款的语义。

Visual C++ 标准库实现可以对这段代码做任何事情,包括默默地删除或忽略 const 限定,它仍然符合标准。

于 2011-02-09T01:45:52.400 回答
1

这根本不应该工作。正如您所说,在 §23.1 ¶ 3 中指定存储在容器中的对象必须是CopyConstructible(如 §20.1.3 中所述)和Assignable.

对 type的Assignable要求T是,作为type t,您可以:uT

t = u

具有T&作为返回值并t等效于u作为后置条件。(§23.1 ¶4)

因此,const类型显然不是Assignable,因为这样做t = u会引发编译错误(§7.1.5.1 ¶5)。

我想这是微软实现中的一个错误。Linux 上的 g++ 会发出典型的 25 kajillion-lines 模板错误,如果您甚至尝试实例化 a vector<const int>(以防万一,在有和没有-std=c++0x标志的情况下都进行了测试)。

顺便说一句,这在IBM FAQ中也有详细说明。


从理论上讲,正如@James McNellis 所说,编译器不需要破坏向量实例化(如果它是未定义的行为,任何事情都可能发生 - 包括一切正常);但是,在赋值语句中存在违反标准的行为,应该会产生编译错误。

事实上,该operator[]成员返回一个vector<const int>::reference; 该值必须是T(§23.1 ¶5 表 66)的左值;因为T是一种const类型,所以它将是一个const左值。所以我们归结为(§7.1.5.1 ¶5),它将尝试对const元素执行分配的代码定义为“格式错误”,这需要编译错误或至少是警告,因为分配给-const是可诊断规则(§1.4 ¶1-2)(未指定“无需诊断”语句)。


最终编辑

实际上,@James McNellis 是对的;一旦你通过实例化调用了未定义的行为vector<const int>,通常的规则就不再具有价值,所以无论它做什么,实现仍然是符合标准的——包括const从元素类型中删除或者生成通常的鼻恶魔。

于 2011-02-09T01:21:52.247 回答