我知道const_cast
的使用不会引入未定义的行为(即,它可以安全使用),只要您使用const_cast
变量即可最初定义为const
,或者如果最初定义为const
,则您不会通过其const_cast
别名对其进行修改。
然而,众所周知,大多数STL容器(例如std::vector
,std::set
)动态分配其内部缓冲区。基于这一事实,我认为将const
定义的std::vector
置于只读内存中是不可能的。
当然,如果上述情况成立,我会假设这种STL容器,即使它们被定义为const
,例如:
std::vector<int> const v;
const_cast
他们通过他们的const_cast
别名改变它们是合法的,并且不会导致任何未定义的行为。
上述假设是否成立或我错了?
答案 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
对象来打破优化程序的假设,可能会产生灾难性且无法预测的后果。