VC++允许对 STL 容器使用 const 类型。为什么?

发布于 2024-10-16 12:44:36 字数 209 浏览 6 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

格子衫的從容 2024-10-23 12:44:36

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

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

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

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

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

特别是,在以下情况下效果未定义:

...

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

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]:

In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard Library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

In particular, the effects are undefined in the following cases:

...

  • for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause.

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.

许仙没带伞 2024-10-23 12:44:36


这根本不应该起作用。正如您所说,在第 §23.1 ¶ 3 节中,指定了存储在容器中的对象必须是CopyConstructible(如第 §20.1.3 节中所指定)和可分配

类型 TAssignable 要求是,tu 类型为 T< /code>,您可以这样做:

t = u

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);由于 Tconst 类型,因此它将是 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) and Assignable.

The Assignable requirements for a type T are that, being t and u of type T, you can do:

t = u

having a T& as return value and t equivalent to u as postcondition. (§23.1 ¶4)

Thus, const types are clearly not Assignable, since doing t = 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 a vector<const int>::reference; that one is required to be an lvalue of T (§23.1 ¶5 table 66); since T is of a const type, it will be a const lvalue. So we fall down to (§7.1.5.1 ¶5), which defines code that tries to perform an assignment to a const 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 the const from the element type or generating the usual nasal demons.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文