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

Al *_*ndy 1 c++ static gcc instance

我有这个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();
}
Run Code Online (Sandbox Code Playgroud)

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


结果:

size() == 1: YES
size() == 1: YES
Run Code Online (Sandbox Code Playgroud)

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

size() == 1: YES
size() == 1: NO
Run Code Online (Sandbox Code Playgroud)

对我来说很明显,使用static不会返回正确的结果,但我很惊讶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符合吗?像这样的代码永远不会是正确的.

asc*_*ler 8

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

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

  2. 在类成员声明中,成员"属于"整个类,而不是类类型的每个对象.

    • 对于数据类成员,只存在一个对象,并且成员名称的使用都引用相同的对象,而不是在每个类对象中具有不同的成员子对象.

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

  3. 在函数内的对象定义中,对该函数的所有调用(顺序或递归)使用的对象确实存在,而不是每次调用该函数都有一个单独的对象.评估对象的初始化程序,并且仅在第一次到达语句时初始化对象.如果它具有类类型,则在exit调用或main返回时,将按照与创建相反的顺序以及其他函数static对象,名称空间成员对象和静态类成员对象来调用析构函数.

(含义1主要来自C语言.含义3也来自C语言,添加了类析构函数的部分.在C中根本找不到含义2.)

在您的代码中,processItems不是static类成员,因此" this"在其中有效. allItems声明为static,但它由函数声明定义,并且根本不是类成员,因此上面的第三个含义适用,第三个含义对this关键字的语义没有影响.您的代码与第三个含义的描述完全相同:初始化程序,它涉及捕获thislambda中的指针,仅在第一次进行评估.

第三个含义根本不需要涉及一个类:

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