const 对象在其构造函数中将其地址分配给指向非常量的指针

const object assigning its address to pointer to non-const in its constructor

为什么下面的代码编译通过后编译器没有报错甚至没有警告? AFAIK,代码有未定义的行为。但是编译器对此保持沉默的原因是什么?

class C1;

class C0 {
public:
    C1* c1{ nullptr };
};

class C1 {
public:
    int i{ 0 };
    C0 c0; 
    C1() { c0.c1 = this; }
};

int main()
{
    const C1 c1; 
    return c1.c0.c1->i = 123;
}

简介:class.ctor

"可以为 constvolatileconst volatile 对象调用构造函数。constvolatile 语义 ( [dcl.type.cv]) 不应用于正在构造的对象。它们在最派生对象 ([intro.object]) 的构造函数结束时生效。"

class C1;

class C0 {
public:
    C1* c1 = nullptr; // c1 is pointing to a non-const C1
};

class C1 {
public:
    int i = 0;
    C0 c0;
    C1() {
        // *this is non-const in the constructor.
        // hence, c1, that is a pointer to a non-const C1 can be assigned
        // to point at this:
        c0.c1 = this;
    };

    void foo() { // However, ...
        // calling this function when *this is const would fail.
        c0.c1 = this;
    }
};

int main() {
    const C1 c1;
    //c1.foo(); // nope

    // now this:
    c1.c0.c1->i = 123;

    // becomes a sneaky way of doing this:
    const_cast<C1&>(c1).i = 123;          // undefined behavior
}

编译器概不负责。它无法跟踪语言允许您规避类型安全的所有可能方式,因此语言标准只是声明 (dcl.type.cv/4):

"任何尝试修改([expr.ass][expr.post.incr][expr.pre.incr])一个const对象([basic.type.qualifier])生命周期 ([basic.life]) 导致未定义的行为。".

标准不强制诊断此问题。

一般情况下很难或不可能确定问题所在。 (当代码被拆分成不同的翻译单元 (TU) 时甚至更多)。

编译器尝试诊断一些未定义的行为 (UB),即使他们不必这样做,以帮助开发人员。

constexpr 更受限制并且不允许 UB(但也不允许有效构造)。

Here

class C1;

class C0 {
public:
    C1* c1{ nullptr };
};

class C1 {
public:
    int i{ 0 };
    C0 c0; 
    constexpr C1() {
        c0.c1 = this;
    }
};

[[maybe_unused]] constexpr C1 c_ok{}; 

constexpr C1 foo()
{
    const C1 c_ko{}; 
    
    c_ko.c0.c1->i = 123;
    return c_ko;
}

[[maybe_unused]] constexpr C1 c_ko = foo(); 

编译器(除了 msvc :-/)检测到 UB 错误类似于

note: modification of object of const-qualified type 'const int' is not allowed in a constant expression.