参考这个指针:GCC vs clang

Reference to the this pointer: GCC vs clang

这是 questions 的后续。

考虑以下代码:

struct A {
private:
    A* const& this_ref{this};
};

int main() {
    A a{};
    (void)a;
}

如果使用 -Wextra 编译,GCC v6.2 and clang v3.9 都会显示警告。

无论如何,在下面显示的稍微修改的版本中,它们的行为有所不同:

struct A {
    A* const& this_ref{this};
};

int main() {
    A a{};
    (void)a;
}

在这种情况下,GCC doesn't give any warning, clang 给出与上一个示例中返回的警告相同的警告。

警告几乎相同。
它遵循来自 clang 的那个:

3 : warning: binding reference member 'this_ref' to a temporary value [-Wdangling-field]

哪个编译器是正确的?

我会说 GCC 在这种情况下是错误的,我正在打开一个问题,但由于该语言的一个神秘的角落情况,它可能是相反的。

成员声明

A* const& this_ref{this};

绑定对仅在构造函数执行期间存在的临时对象的引用(注意:this 是右值表达式)。

我不确定 this 是否在该上下文中正式可用,但如果使用该指针,则说明 UB 严重。

回复

Which compiler is right?

…编译器可以根据需要发出任意数量的诊断信息。发布诊断并没有错。所以根据你的描述,两者都接受代码,那么要么两个编译器都是正确的(我认为这很可能),要么都是错误的。

此警告的原因是 IMO 标准 (12.2.5) 的摘录:

A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.

并且由于 keyword this is a prvalue expression,在 this_ref 初始化期间将创建一个临时文件,并且 this_ref 绑定到该临时文件。

但我怀疑你的引用是否真的在 ctor-initializer 中初始化过。

如果你写:

struct A {
private:
    const int& rr = 1+1;
};

然后您将使用 gcc 重现完全相同的问题,删除 private 也会删除此警告。

据我所知,this pointer 可能会用在非静态成员函数的主体中,我从未读过它可以在默认成员初始化期间用作参数。

thisprvalue, and temporary object will be created when binding reference to a prvalue, so you're binding reference member to a temporary in default member initializer.

并且在默认成员初始值设定项中将引用成员绑定到临时成员的格式不正确,这是由标准明确规定的。

$12.6.2/11 初始化基地和成员 [class.base.init]:

A temporary expression bound to a reference member from a default member initializer is ill-formed. [ Example:

struct A {
  A() = default;          // OK
  A(int v) : v(v) { }     // OK
  const int& v = 42;      // OK
};
A a1;                     // error: ill-formed binding of temporary to reference
A a2(1);                  // OK, unfortunately

— end example ]

参见CWG 1696,这适用于 C++14。