使用未初始化指针访问静态类成员属于未定义行为吗?

3

针对此问题的一个后续问题。

我们有以下代码:

#include <iostream>

struct A 
{
    static int n;
};

int A::n = 5;

int main() 
{
    A* a; //uninitialized on purpose
    std::cout << a->n; //UB?
}

这种访问方式是否是未定义行为?一方面,访问静态类成员不需要对象,另一方面,对未初始化的指针使用operator->容易出问题。

注意:GCC和MSVC编译此代码时没有任何警告,而Clang则对未初始化的使用进行了投诉。 https://godbolt.org/z/Gy5fR2


类似的问题在这里(https://dev59.com/xl4b5IYBdhLWcg3w9Fyr),尽管我对最佳答案持怀疑态度。 - M.M
我重新打开了这个问题,因为重复的问题涉及空指针,而这个问题涉及未初始化的指针。由于不清楚将*应用于空指针是否是UB(未定义行为),所以这两个问题是不同的。 - Brian Bi
@Yksisarvinen 好的,我已经冒险回答了另一个问题。 - M.M
1
@curiousguy 我同意你的观点。我不明白为什么委员会不能花更多时间来解决这些问题(毕竟,它现在比以往任何时候都有更多的成员)。至少,在引入更多问题的内存/对象模型的进一步“改进”之前,我认为应该先解决这种问题。 - Brian Bi
显示剩余5条评论
1个回答

10
a->n的语义是对*a进行求值,但不会访问它,因为数据成员是静态的。参见C++17 [expr.ref]:

......点或箭头之前的后缀表达式被求值......表达式E1->E2转换为等价形式(*(E1)).E2......

还有一个脚注说:

如果类成员访问表达式被求值,则即使子表达式的结果不必要确定整个后缀表达式的值,例如如果id表达式表示静态成员,子表达式评估也会发生。

在这种情况下,表达式*a被求值。由于a是未初始化的自动变量,应用[dcl.init]/12:

如果评估产生不确定值,则行为未定义,除了以下情况:[ ...... ]

显然对*a进行求值需要访问指针变量a的值,该值是不确定的,因此属于未定义行为(UB)。

那个脚注的理由:https://dev59.com/a6Lia4cB1Zd3GeqPk4-- - M.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接