[英]Segfault when using std::function class member with compiler optimizations
I have a quite simple code example which crashes when optimized with -O2
under gcc 8.2.0 我有一个非常简单的代码示例,当在gcc 8.2.0下使用
-O2
进行优化时崩溃
#include <vector>
#include <functional>
#include <iostream>
template<typename T, typename Container>
class Lambda_Expression
{
using Lambda = std::function<T()>;
const Lambda & _lambda;
public:
Lambda_Expression(const Lambda & l) : _lambda(l) {}
T operator[](const std::size_t i)
{
std::cerr << "inside expression [] " << i << std::endl;
return _lambda();
}
};
auto lambda = []() -> double
{
return 1.0;
};
int main()
{
int N = 10;
std::vector<double> res(N, 0.0);
double x = lambda();
std::cerr << "before for loop " << x << std::endl;
auto test_expression = Lambda_Expression<double, std::vector<double>>(lambda);
for( int idx=0; idx<N; ++idx )
{
std::cerr << "loop " << idx << std::endl;
double x = test_expression[idx];
}
}
Using also -std=c++17
, in case that makes a difference. 使用
-std=c++17
,如果-std=c++17
。
I get 我明白了
before for loop 1
loop 0
inside expression [] 0
[1] 5288 segmentation fault ./bench_lambdas
whereas I would expect the loop to run for 10 iterations. 而我希望循环运行10次迭代。 This segfault does not appear with optimization level less than 2.
优化级别小于2时,此段错误不会出现。
The above example looks like fairly harmless code to me and as far as I know level 2 optimizations should not break correct code. 上面的例子看起来对我来说是相当无害的代码,据我所知,2级优化不应该破坏正确的代码。
Question: Is there undefined behaviour or incorrect code in my example or what might be the issue? 问题:我的示例中是否存在未定义的行为或错误的代码,或者可能是什么问题?
As far I know, it's undefined behaviour. 据我所知,这是未定义的行为。
The problem is that your class register the reference 问题是您的类注册了引用
// ..........V reference !!!
const Lambda & _lambda;
of the argument of the constructor 构造函数的参数
Lambda_Expression(const Lambda & l) : _lambda(l) {}
that is a std::function
这是一个
std::function
using Lambda = std::function<T()>;
But when you call the constructor with a lambda (as in main()
) 但是当你用lambda调用构造函数时(如在
main()
)
auto test_expression = Lambda_Expression<double, std::vector<double>>(lambda);
you save in _lambda
the reference to a temporary object because lambda
isn't a std::function
so it's created a temporary object, of type std::function<double()>
, initialized with lambda
. 你在
_lambda
保存对临时对象的引用,因为lambda
不是std::function
所以它创建了一个临时对象,类型为std::function<double()>
,用lambda
初始化。
So the problem: the reference to the temporary object become a dangling reference at the end of the construction of test_expression
so, when you call test_expression[idx]
, you use _lambda
that is pointing (potentially) to garbage. 所以,问题:引用了临时对象成为施工结束悬空参考
test_expression
所以,当你调用test_expression[idx]
您使用_lambda
被指向(可能)垃圾。
I suggest to avoid this sort of problems avoiding the reference part (make _lambda
a regular member of type std::function
我建议避免这种避免引用部分的问题(make
_lambda
是std::function
类型的常规成员
const Lambda _lambda; // <-- no more reference
so you copy the temporary object) 所以你复制临时对象)
But if you really want that _lambda
is a reference to a std::function
, you should write something as follows 但是如果你真的想要
_lambda
是对std::function
的引用,你应该写如下内容
std::function<double()> f{lambda};
auto test_expression = Lambda_Expression<double, std::vector<double>>{f};
This way the constructor receive a reference to a std::function
object ( f
) that survive to his call. 这样,构造函数接收对
std::function
对象( f
)的引用,该对象在其调用后仍然存在。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.