const_cast const STL 容器,它是未定义的行为

const_cast const STL container, is it undefined behavior?

本文关键字:const 未定义 cast STL 容器      更新时间:2023-10-16

我知道使用const_cast不会引入未定义的行为(即使用它是安全的),只要您const_cast的变量最初没有定义为const,或者如果它最初被定义为const您没有通过其const_cast ed别名对其进行修改。

然而,众所周知,大多数STL容器(例如,std::vectorstd::set)动态分配其内部缓冲区。基于这一事实,我认为不可能将const定义的std::vector放在只读内存中。

当然,如果上述情况成立,我假设这种STL容器即使被定义为const,例如:

std::vector<int> const v;
const_cast它们并通过

const_cast ed别名更改它们是合法的,不会导致任何未定义的行为。

上述假设成立还是我错了?

C++标准明确指出,丢弃通过 new const T 创建的对象的const并对其进行修改是未定义的行为。

例如,C++11 标准在其 §7.1.6.1/4 中包含此示例:

const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object

标准中的例子是非规范性的,只是例子,可能是错误的。例如,在C++03中,几乎所有使用<iostream>的例子都是错误的(当时正式有必要也包括<ostream>,但这不是委员会的意图),而C++03 §5/4中的表达例子是错误的,说行为是未指定的而不是未定义的(这可能反映了原始意图)。但是,上面的例子是正确的。

这表明动态分配的内存不需要是可变的:修改它可能会有未定义的行为。

但是,例如,当创建一个std::string时,它对缓冲区的分配(如果有的话)发生在构造函数的执行期间,此时对象尚未const,并且缓冲区未分配为const。因此,如果分配了一个缓冲区,则最初不是const的。但是对于这个特定示例,std::string可以使用小缓冲区优化,其中它直接在对象中使用存储,然后最初将const存储(可能在只读内存中分配)。这涉及到规则的合理性,即不能修改任何原始const对象。


除了只读内存方案之外,UB 的基本原理还包括它可以为编译器提供优化可能性。

正如胡安乔潘扎在对这个问题的评论中指出的那样,

"优化器使用它来做各种疯狂的事情,假设const对象不会被修改。

通过修改最初const的对象来打破优化程序的假设,可能会产生灾难性且实际上不可预测的后果。

相关文章: