c – 从“this”中抛弃constness然后更改成员值会调用未定义的行为吗?

前端之家收集整理的这篇文章主要介绍了c – 从“this”中抛弃constness然后更改成员值会调用未定义的行为吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
回复我对某些 answer in another question评论时,有人建议像
void C::f() const
{
  const_cast<C *>( this )->m_x = 1;
}

因为修改了const对象,所以会调用未定义的行为.这是真的?如果不是,请引用C标准(请提及您引用的标准),以获得此标准.

对于它的价值,我总是使用这种方法来避免使一个成员变量可变,如果只需要一两个方法写入它(因为使用mutable使其可写入所有方法).

解决方法

(尝试)修改const对象(C 11中的7.1.6.1/4)是未定义的行为.

所以重要的问题是,什么是const对象,并且m_x是一个?如果是,那么你有UB.如果不是,则此处没有任何内容表明它将是UB – 当然,由于此处未指出的其他原因(例如,数据竞争),它可能是UB.

如果在类C的const实例上调用函数f,则m_x是一个const对象,因此行为未定义(7.1.6.1/5):

const C c;
c.f(); // UB

如果在类C的非const实例上调用函数f,则m_x不是const对象,因此我们知道行为是定义的:

C c;
const C *ptr = &c;
c->f(); // OK

所以,如果你编写这个函数,那么你的用户不能创建一个C的const实例并在其上调用函数.也许C的实例只能由某个工厂创建,在这种情况下,您可以防止这种情况发生.

如果您希望数据成员可修改,即使完整对象是const,那么您应该将其标记为可变.这就是mutable的用途,即使在C的const实例上调用f,它也会为您提供定义的行为.

从C11开始,const成员函数和对可变数据成员的操作应该是线程安全的.否则,当您的类型与标准库函数和容器一起使用时,您违反了标准库提供的保证.

所以在C 11中你需要使m_x成为原子类型,或者以其他方式同步修改,或者作为最后的文档,即使它被标记为const,函数f也不是线程安全的.如果你没有做任何这些事情,那么你再次创造了一个机会让用户编写他们合理认为应该工作但实际上有UB的代码.

猜你在找的C&C++相关文章