const_cast const STL 容器,是否为未定义行为?

const_cast const STL container, is it undefined behavior?

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

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

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

std::vector<int> const v;

const_cast通过他们的 const_casted 别名修改它们是合法的,不会导致任何未定义的行为。

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

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

标准中的例子是non-normative,只是例子,可能是错误的。例如,在 C++03 中,几乎所有使用 <iostream> 的示例都是错误的(当时正式需要也包括 <ostream>,但这不是委员会的意图),并且C++03 §5/4 中的表达式示例是错误的,表示行为未指定而不是未定义(这可能反映了初衷)。但是,上面的例子是正确的。

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

但是,例如a std::string 被创建,其缓冲区(如果有的话)的分配发生在构造函数的执行期间,此时对象尚未 const,并且缓冲区未分配为 const.所以缓冲区,如果分配了一个,原来不是const。但是对于这个特定的例子,std::string 可能会使用小缓冲区优化,它直接在对象中使用存储,然后最初是 const(可能分配在只读内存中)。这符合 no 最初 const 对象可以修改的规则。


除了 read-only 内存场景之外,UB 的基本原理还包括它可以为编译器提供优化的可能性。

juanchopanza notes in ,

Optimizers use this to do all kind of crazy stuff that assumes const objects won't be modified.

通过修改最初的 const 对象来打破优化器的假设,可能会造成灾难性的且实际上无法预测的后果。