const_cast与可变和未定义的行为

const_cast vs mutable and undefined behavior

提问人:asimes 提问时间:11/16/2023 最后编辑:asimes 更新时间:11/16/2023 访问量:174

问:

编辑:我在这里编辑了代码以不使用指针,因为有太多不相关的评论

#include <iostream>

struct Foo {
    Foo(const int a) : total(a) {}

    int       index = 0;
    const int total;
};

struct Bar {
    Bar(const int a) : total(a) {}

    mutable int index = 0;
    const int   total;
};

int main() {
    const Foo foo(3);
    for (
        ;
        foo.index < foo.total;
        const_cast<Foo*>(&foo)->index++ // 1. Undefined behavior because foo is const
    )
        std::cout << "Foo " << foo.index << std::endl;

    const Bar bar(3);
    for (
        ;
        bar.index < bar.total;
        bar.index++ // 2. Not undefined behavior because of mutable?
    )
        std::cout << "Bar " << bar.index << std::endl;

    return 0;
}

据我所知,标记为 的行是未定义的行为,因为是一个对象,无论如何都用于修改对象// 1. Undefined behavior because foo is constfooconstconst_cast

但是,我不确定是否存在与标有 .它本质上是通过使用而不是// 2. Not undefined behavior because of mutable?mutableconst_cast

那么我的问题是,是否存在具有成员的对象会导致未定义行为的情况constmutable

C++ undefined-behavior 可变常 量转换

评论


答:

7赞 Hugh Granger 11/16/2023 #1

字段从来都不是常量,因此永远不能使用const_cast调用 UB。这是不同的行为,因为理论上 #1 可以将索引放在 rom 中mutable

评论

1赞 asimes 11/16/2023
我担心的是,这是一个对象,本质上意味着该对象仍在变异。是否阻止编译器对对象整体未被修改或仅对该成员做出假设?fooconstmutableconstmutable
2赞 463035818_is_not_an_ai 11/16/2023
@asimes 就是那个成员。当它是时,它不是.编译器不会假定它是mutableconstconst
3赞 user17732522 11/16/2023
@asimes const 对象的成员子对象本身不是 const 对象,并且 const 对象的任何特殊规则(例如不允许修改它)都不适用于它。包含对象和其他不可变的子对象仍然是常量对象,因此不能修改。(请参阅标准中的 eel.is/c++draft/basic.type.qualifier#1.1mutable
1赞 Brian61354270 11/16/2023
@user17732522 这可能值得做出自己的答案
3赞 user17732522 11/16/2023 #2

const 对象的可变成员子对象本身不是 const 对象,并且 const 对象的任何特殊规则(例如不允许修改它)都不适用于它。

以递归方式,包含完整对象和该子对象的其他不可变子对象仍然是常量对象,因此不能修改。

const 对象的定义可以在标准的 [basic.type.qualifier/1.1] 中找到:

(1.1) const 对象是 const 对象的类型对象或不可更改的子对象。const T

因此,修改成员子对象或其任何子对象总是可以的,即使包含对象是 ,但这仅适用于可变成员。是否涉及任何内容无关紧要。mutableconstconst_cast

但是,这仅涵盖可变子对象的实际修改,即对自身或其(标量)子对象之一的内置赋值。仍然不允许通过 placement-new 将可变子对象替换为新对象。关于替换 const 对象的相关规则是,任何新对象都不能放置在任何已经或将被自动、静态或线程本地存储持续时间的 const-complete 对象占用的存储中。在您的例子中,是一个 const 对象和一个完整的对象。它具有自动存储持续时间,可变子对象占用其部分存储。bar