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
"可以为 const
、volatile
或 const volatile
对象调用构造函数。const
和 volatile
语义 ( [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(但也不允许有效构造)。
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.
为什么下面的代码编译通过后编译器没有报错甚至没有警告? 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
"可以为 const
、volatile
或 const volatile
对象调用构造函数。const
和 volatile
语义 ( [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(但也不允许有效构造)。
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.