const_cast const STL容器,是不确定的行为?

时间:2016-01-26 12:37:18

标签: c++ c++11 stl undefined-behavior const-cast

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

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

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

std::vector<int> const v;

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

上述假设是否成立或我错了?

1 个答案:

答案 0 :(得分:4)

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

例如,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(可能在只读存储器中分配)。这符合 no 原始const对象可以修改的规则的合理性。

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

juanchopanza中的a comment to the question注释,

  

优化器使用它来执行各种疯狂的事情,假定const个对象不会被修改。

通过修改原始const对象来打破优化程序的假设,可能会产生灾难性且无法预测的后果。