c++ const_cast与可变和未定义的行为

2lpgd968  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(76)

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

#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 const的行是未定义的行为,因为fooconst对象,而const_cast无论如何都被用于修改该对象
然而,我不确定是否有任何可能的未定义行为与标记为// 2. Not undefined behavior because of mutable?的行有关。
那么我的问题是,是否存在具有mutable成员的const对象会导致未定义行为的情况

eqoofvh9

eqoofvh91#

一个mutable字段永远不是const,因此永远不能用const_cast调用UB。这是不同的行为,因为理论上#1可以在rom中放置索引。

piv4azn7

piv4azn72#

const对象的可变成员子对象本身不是const对象,并且不适用于const对象的任何特殊规则,例如不允许修改它。
递归地,包含完整对象和该子对象的其他不可变子对象仍然是常量对象,因此不能被修改。

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

(1.1)const objectconst T类型的对象或const对象的不可变子对象。
所以修改mutable成员子对象或它的任何子对象总是可以的,即使包含对象是const,但这只适用于可变成员。是否涉及任何const_cast都无关紧要。
然而,这只涵盖了可变子对象的实际修改,也就是说,内置赋值给自身或它的一个(标量)子对象。仍然不允许的是通过placement-new用新对象 * 替换 * 可变子对象。关于替换const对象的相关规则是,任何新对象都不能放置在任何已经或将要被const占用的存储中-自动、静态或线程本地存储持续时间的完整对象。在您的示例中,bar是一个const对象和完整对象。它具有自动存储持续时间,可变子对象占用其部分存储。

相关问题