提问者:小点点

通过const_cast删除const并调用不修改结果对象的非const函数是否安全?


我知道抛弃const-ness应该小心,任何从最初的const对象中删除const-ness并随后修改对象的尝试都会导致未定义的行为。如果我们想删除const-ness以便我们可以调用一个不修改对象的非const函数怎么办?我知道我们实际上应该标记这样的函数const,但是假设我使用的是一个没有可用的const版本的“坏”代码。

所以,总而言之,下面的代码是“安全的”吗?我的猜测是,只要你最终不修改对象,你就没问题,但我不是100%确定。

#include <iostream>

struct Foo
{
    void f() // doesn't modify the instance, although is not marked const
    {
        std::cout << "Foo::f()" << std::endl;
    }
};

int main()
{
    const Foo foo;
    const_cast<Foo&>(foo).f(); // is this safe?
}

共3个答案

匿名用户

关于const_cast的未定义行为由C 11标准的§3.8/9(§3.8是对象生命周期)定义:

"在具有静态、线程或自动存储持续时间的const对象占用的存储位置创建新对象,或者在此类const对象在其生命周期结束前占用的存储位置创建新对象会导致未定义的行为。

和§7.1.6.1/4(§7.1.6.1是cv限定词)

“除了可以修改任何声明为mutable(7.1.1)的类成员外,任何在其生命周期(3.8)内修改const对象的尝试都会导致未定义的行为。

换句话说,如果您修改了最初的const对象,则会获得UB,否则1不会。

const_cast本身没有引入UB。

在§5.2.11/7中还有一个非规范性的注释,即“取决于类型”,通过从const_cast获得的指针或引用写入可能具有未定义的行为。

这个非规范性注释非常模糊,以至于它有自己的非规范性脚注,这解释了“const_cast不限于抛弃const-限定符的转换”。

然而,尽管如此,我还是想不出任何情况下写作可以被很好地定义或不取决于类型,也就是说,我无法理解这篇笔记。这里的另外两个答案集中在这篇笔记中的“写”这个词上,这是通过3.8/9进入UB-land所必需的,是的。对我来说,相当可疑的方面是“取决于类型”,这似乎是那篇笔记的重要部分。

1)除了关于其他非const_cast相关事物的UB规则发挥作用之外,例如,将稍后在typeid-表达式以外的上下文中取消引用的指针置为空。

匿名用户

这个特定的示例恰好是安全的(具有明确定义的行为),因为没有写入声明为const的对象。

匿名用户

我们在[dcl.type.cv]中有这个:

除了可以修改任何声明为mutable(7.1.1)的类成员外,任何在其生命周期(3.8)内修改const对象的尝试都会导致未定义的行为。

[expr. const.cast]中有一个注释(非规范性),其中指出:

[注意:根据对象的类型,通过指针、左值或指向数据成员的指针进行写操作,该操作由const_cast产生,该操作会丢弃const-限定符,可能会产生未定义的行为(7.1.6.1)。

const_cast之后尝试修改对象或写操作[可能]会导致未定义的行为。这里,我们没有写操作。