VC++允许对 STL 容器使用 const 类型。为什么?
STL 容器要求存储的值是可复制构造和可赋值的。 const T 显然不是任何 T 的可分配类型,但我尝试使用它(只是出于好奇)并发现它可以编译,而且表现为可分配类型。
vector<const int> v(1);
v[0] = 17;
这在 Visual Studio 2008 中成功运行并将 v[0] 分配给 17。
STL containers require the stored values to be copy constructible and assignable. const T is obviously not an assignable type for any T, but I tried to use it (just being curious) and found out that it compiles and, moreover, behaves as an assignable type.
vector<const int> v(1);
v[0] = 17;
This successfully runs in Visual Studio 2008 and assigns v[0] to 17.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如其他人所建议的那样,这并不是实施中的错误。
违反 C++ 标准库设施的要求不会导致程序格式错误,而是会产生未定义的行为。
您违反了存储在容器中的值类型必须是可复制构造和可分配的要求(显然,const 类型不可分配),因此您的程序表现出未定义的行为。
C++ 标准中适用的语言可以在 C++03 17.4.3.6 [lib.res.on.functions] 中找到:
Visual C++ 标准库实现可以对此代码执行任何操作,包括静默删除或忽略 const 限定,并且它仍然符合标准。
This is not a bug in the implementation as others have suggested.
Violating the requirements of a C++ Standard Library facility does not render your program ill-formed, it yields undefined behavior.
You have violated the requirement that the value type stored in a container must be copy constructible and assignable (
const
types are not assignable, obviously), so your program exhibits undefined behavior.The applicable language from the C++ Standard can be found in C++03 17.4.3.6 [lib.res.on.functions]:
The Visual C++ Standard Library implementation may do anything with this code, including silently removing or ignoring the const-qualification, and it is still standards-conforming.
这根本不应该起作用。正如您所说,在第 §23.1 ¶ 3 节中,指定了存储在容器中的对象必须是
CopyConstructible
(如第 §20.1.3 节中所指定)和可分配
。类型
T
的Assignable
要求是,t
和u
类型为T< /code>,您可以这样做:
将
T&
作为返回值,将t
等价于u
作为后置条件。 (§23.1 ¶4)因此,
const
类型显然不可可赋值
,因为执行t = u
会引发编译错误(§7.1. 5.1¶5)。我认为这是微软实施中的一个错误。如果您尝试实例化
vector
(使用和不使用-std=c++0x
进行测试,Linux 上的 g++ 会发出典型的 25 kajillion-lines 模板错误)代码> 标志,以防万一)。顺便说一句,这也在 IBM 常见问题解答。
理论上,正如 @James McNellis 所说,编译器不需要在向量实例化上崩溃(如果它是未定义的行为,任何事情都可能发生 - 包括一切正常);但是,在赋值语句中违反了标准,应该会产生编译错误。
事实上,
operator[]
成员返回一个vector::reference
;该值必须是T
的左值(§23.1 ¶5 表 66);由于T
是const
类型,因此它将是const
左值。因此,我们陷入 (§7.1.5.1 ¶5),它将尝试对const
元素执行赋值的代码定义为“格式错误”,这需要一个编译错误或至少警告,因为赋值给const
是一个可诊断的规则(§1.4 ¶1-2)(未指定“无需诊断”语句)。最终编辑
实际上,@James McNellis 是对的;一旦您通过实例化
vector
调用了未定义的行为,通常的规则就不再有价值,因此无论它做什么,实现仍然符合标准 - 包括删除const 从元素类型或生成通常的鼻恶魔。
This simply shouldn't work. At §23.1 ¶ 3 it's specified, as you said, that objects stored in a container must be
CopyConstructible
(as specified at §20.1.3) andAssignable
.The
Assignable
requirements for a typeT
are that, beingt
andu
of typeT
, you can do:having a
T&
as return value andt
equivalent tou
as postcondition. (§23.1 ¶4)Thus,
const
types are clearly notAssignable
, since doingt = u
would raise a compilation error (§7.1.5.1 ¶5).I suppose that this is a bug in Microsoft implementation. g++ on Linux emits the typical 25 kajillion-lines template error if you even try to instantiate a
vector<const int>
(tested both with and without the-std=c++0x
flag, just in case).By the way, this is also explained in detail in this IBM FAQ.
In theory, as @James McNellis said, the compiler is not required to blow up on the vector instantiation (if it's undefined behavior anything can happen - including everything working fine); however, on the assignation statement there's a violation of the standard that should produce a compilation error.
In facts, the
operator[]
member returns avector<const int>::reference
; that one is required to be an lvalue ofT
(§23.1 ¶5 table 66); sinceT
is of aconst
type, it will be aconst
lvalue. So we fall down to (§7.1.5.1 ¶5), which defines code that tries to perform an assignment to aconst
element as "ill-formed", and this demands a compilation error or at least a warning, because assignment-to-const
is a diagnosable rule (§1.4 ¶1-2) (no "no diagnostic is required" statement is specified).Final edit
Actually, @James McNellis is right; once you've invoked undefined behavior by instantiating
vector<const int>
, the usual rules stop having value, so the implementation is still standard-conforming whatever it does - including removing theconst
from the element type or generating the usual nasal demons.