为什么 gcc 7.3 在静态定义中接受 'this'?

Why is gcc 7.3 accepting 'this' in a static definition?

我有这个 MCVE:

#include <functional>
#include <vector>
#include <stdio.h>

class VectorInside
{
    public:
        std::vector<int>    classVector;
        auto processItems() -> void;
};

using foo = struct foo
{
    std::function<bool()>   someLambda;
};

auto VectorInside::processItems() -> void
{
    static std::vector<foo> allItems =
    {
        { [&] () -> bool { return 1 == this->classVector.size(); } }
    };
    for ( auto const & currentItem : allItems )
    {
        printf( "size() == 1: %s\n", true == currentItem.someLambda() ? "YES" : "NO" );
    }
}

int main()
{
    VectorInside test1, test2;
    test1.classVector.resize(1);

    test1.processItems();
    test2.processItems();
}

在我看来 gcc 不应该编译这段代码,因为很明显 allItemsstatic 定义采用了第一个调用的 VectorInside 实例因此,每个后续调用 return 的大小仅为 test1 的大小,即第一个调用 processItems().


结果:

size() == 1: YES
size() == 1: YES

删除 static 给出了正确的结果,因为 processItems() 的每次调用都会生成 allItems.

fresh 内容
size() == 1: YES
size() == 1: NO

对我来说,很明显使用 static 不会 return 正确的结果,但我很惊讶 gcc 7.3 接受了这个代码。


技术资料:

gcc 7.3 编译它的选项: -O3 -std=c++17 -Wall -Werror -Wextra -fsanitize=undefined -fsanitize=address -fno-omit-frame-pointer -pedantic -pedantic-errors


我的问题:

这个C++17符合吗?这样的代码永远不会正确。

关键字static有三四个完全不同的含义!

  1. 在命名空间成员声明中,名称具有内部链接(与在不同翻译单元中找到的任何名称不同)。

  2. 在 class 成员声明中,成员 "belongs to" 是 class 的一个整体,而不是 class 类型的每个对象。

    • 对于一个数据class成员,只有一个对象存在,成员名称的使用都指代同一个对象,而不是每个[=56中有不同的成员子对象=]对象.

    • 对于class成员函数,可以在没有class类型对象的情况下调用该函数,并且this关键字在其内部无效定义.

  3. 在函数内的对象定义中,所有对该函数的调用(顺序或递归)只存在一个对象,而不是为每个函数调用使用一个单独的对象。评估对象的初始化程序,并且仅在第一次到达语句时初始化对象。如果它有一个 class 类型,当调用 exitmain returns 时调用析构函数,与其他函数的创建顺序相反 - static 对象、命名空间成员对象和静态 class 成员对象。

(意思1主要取自C语言,意思3也是取自C语言,增加了class析构函数的部分,意思2在C中完全没有。)

在您的代码中,processItems 不是 static class 成员,因此“this”在其中有效。 allItems声明为static,但它是通过函数语句定义的,根本不是class成员,所以适用上面的第三个意思,第三个意思没有作用关于 this 关键字的语义。您的代码完全符合第三个含义的描述:初始化程序,涉及在 lambda 中捕获 this 指针,仅在第一次评估。

第三个意思根本不需要涉及class:

// Returns a different sequential value on each call (until overflow)
unsigned int nextValue() {
    static unsigned int counter = 0;
    return counter++;
}