假设我有一个结构定义:
struct thing
{
thing* x;
int z;
thing() : x(this), z(0) {}
void foo() const
{
this->x->z++;
}
};
请注意,我创建了一个指向自己的可变指针(邪恶的笑声)
然后我可以像这样稍后使用它:
int main()
{
const thing c;
c.foo();
assert(c.z == 1);
c.foo();
assert(c.z == 2);
return c.z;
}
正如您所看到的,我似乎可以更改一个常量值...这是UB吗?
答案 0 :(得分:10)
[dcl.type.cv] p4:
除了任何声明为
mutable
([dcl.stc])的类成员可以 已修改,任何修改尝试([expr.ass],[expr.post.incr], [expr.pre.incr])常量对象([basic.type.qualifier]) 寿命([basic.life])导致行为不确定。
[basic.type.qualifier] p1:
常量对象是
const T
类型的对象或该对象的不可更改子对象。
c.z
是const对象,因为它是c
的不可更改子对象。您的代码尝试在其生命周期内对其进行修改。因此,该代码具有未定义的行为。
答案 1 :(得分:0)
foo
函数本身就可以了,因为const
之类的T::foo() const
成员函数只是表明this
的类型为const *T
;这样,(非常量)成员指向同一对象这一事实就无关紧要。
首先将对象c
声明为const。因此,UB通过任何代码(包括(本身正确的)成员函数c
)更改foo
的内容。