STL 容器要求存储的值是可复制构造和可分配的。const T 显然不是任何 T 的可分配类型,但我尝试使用它(只是好奇)并发现它可以编译,而且,它表现为可分配类型。
vector<const int> v(1);
v[0] = 17;
这在 Visual Studio 2008 中成功运行并将 v[0] 分配给 17。
STL 容器要求存储的值是可复制构造和可分配的。const T 显然不是任何 T 的可分配类型,但我尝试使用它(只是好奇)并发现它可以编译,而且,它表现为可分配类型。
vector<const int> v(1);
v[0] = 17;
这在 Visual Studio 2008 中成功运行并将 v[0] 分配给 17。
正如其他人所建议的那样,这不是实施中的错误。
违反 C++ 标准库设施的要求不会使您的程序格式错误,它会产生未定义的行为。
您违反了存储在容器中的值类型必须是可复制构造和可分配的要求(const
显然,类型不可分配),因此您的程序表现出未定义的行为。
C++ 标准中适用的语言可以在 C++03 17.4.3.6 [lib.res.on.functions] 中找到:
在某些情况下(替换函数、处理函数、对用于实例化标准库模板组件的类型的操作),C++ 标准库依赖于 C++ 程序提供的组件。如果这些组件不满足其要求,则标准对实施没有要求。
特别是,在以下情况下效果是不确定的:
...
- 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作未实现适用的要求子条款的语义。
Visual C++ 标准库实现可以对这段代码做任何事情,包括默默地删除或忽略 const 限定,它仍然符合标准。
这根本不应该工作。正如您所说,在 §23.1 ¶ 3 中指定存储在容器中的对象必须是CopyConstructible
(如 §20.1.3 中所述)和Assignable
.
对 type的Assignable
要求T
是,作为type t
,您可以:u
T
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
从元素类型中删除或者生成通常的鼻恶魔。