为什么 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
不应该编译这段代码,因为很明显 allItems
的 static
定义采用了第一个调用的 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
有三四个完全不同的含义!
在命名空间成员声明中,名称具有内部链接(与在不同翻译单元中找到的任何名称不同)。
在 class 成员声明中,成员 "belongs to" 是 class 的一个整体,而不是 class 类型的每个对象。
对于一个数据class成员,只有一个对象存在,成员名称的使用都指代同一个对象,而不是每个[=56中有不同的成员子对象=]对象.
对于class成员函数,可以在没有class类型对象的情况下调用该函数,并且this
关键字在其内部无效定义.
在函数内的对象定义中,所有对该函数的调用(顺序或递归)只存在一个对象,而不是为每个函数调用使用一个单独的对象。评估对象的初始化程序,并且仅在第一次到达语句时初始化对象。如果它有一个 class 类型,当调用 exit
或 main
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++;
}
我有这个 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
不应该编译这段代码,因为很明显 allItems
的 static
定义采用了第一个调用的 VectorInside
实例因此,每个后续调用 return 的大小仅为 test1
的大小,即第一个调用 processItems()
.
结果:
size() == 1: YES
size() == 1: YES
删除 static
给出了正确的结果,因为 processItems()
的每次调用都会生成 allItems
.
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
有三四个完全不同的含义!
在命名空间成员声明中,名称具有内部链接(与在不同翻译单元中找到的任何名称不同)。
在 class 成员声明中,成员 "belongs to" 是 class 的一个整体,而不是 class 类型的每个对象。
对于一个数据class成员,只有一个对象存在,成员名称的使用都指代同一个对象,而不是每个[=56中有不同的成员子对象=]对象.
对于class成员函数,可以在没有class类型对象的情况下调用该函数,并且
this
关键字在其内部无效定义.
在函数内的对象定义中,所有对该函数的调用(顺序或递归)只存在一个对象,而不是为每个函数调用使用一个单独的对象。评估对象的初始化程序,并且仅在第一次到达语句时初始化对象。如果它有一个 class 类型,当调用
exit
或main
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++;
}