Max*_*hof 5 c++ reference constants language-lawyer
简而言之:以下代码是否有未定义的行为,或者这样可以吗?
struct X
{
X(int b)
: value(b)
, ref(value)
{
}
int value;
int& ref;
void isThisUB() const
{
ref = 1;
}
};
int main()
{
const X x(2);
// Is either of these fine?
x.isThisUB();
x.ref = 3;
return x.value;
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/1TE9a7M4a
X::value是常量x。根据我对const语义的理解,这意味着以任何方式修改它都是UB。然而,我们可以在构造函数中获取对它的非常量引用,然后通过它来修改它,无论是在const成员函数中还是直接修改。
C++(至少 17)标准在[dcl.type.cv]中给出了与 const 相关的 UB 示例,它看起来基本相同,只是它使用const_cast. 注意如何p->x.j = 99表示为 UB。我没有看到使用const_cast上面的代码实现这一点有根本的区别。
那么,上面的代码是UB吗?非常量引用成员/指针真的有这么大吗?
(如果你能想出产生相关问题的搜索关键字,而不仅仅是随机的const东西,我会印象深刻。)
下面的代码是否有未定义的行为,或者这样可以吗?
它有UB。标准说:
[dcl.type.cv]
除了声明为可变的任何类成员都可以修改之外,任何在其生命周期内修改 const 对象的尝试都会导致未定义的行为。
x是 const 并且您修改其非可变成员。
我不认为使用 const_cast 实现这一点与我上面的代码有根本区别。
的确。出于同样的原因,两者都是 UB。
非常量引用成员/指针真的有这么大吗?
footgun 的触发因素是对象在其构造函数内时暂时为非常量。因此,对非常量“this”及其子对象的指针和引用在构造函数中很容易获得,无论该对象是否是 const。因此我们可以得出结论,存储这些指针/引用以供以后使用是不明智的。
由于其他几个原因,将指针和引用存储为引用“this”的成员也很危险。它们需要存储,如果您要直接通过其名称访问引用的成员,则不需要这些存储。此外,您会发现该类的复制语义可能不是您想要的。
如果您想指向多个替代方案中的一个成员,请使用成员指针,而不是对象指针/引用(在这种情况下无法避免使用存储)。这解决了复制和意外的 const 违规问题。