gpt4 book ai didi

当函数是从存储在夹具结构中的对象构建时,C++ Lambda 构建静态函数返回意外值

转载 作者:行者123 更新时间:2023-11-30 02:45:15 25 4
gpt4 key购买 nike

我有一个函数,它接受一个对象 vector ,将 lambda 表达式存储为类成员。该类还有一个静态函数,它采用这些对象的 vector 并创建一个 lambda 来对每个对象的 lambda 值求和。为了测试构建器函数,我创建了一个测试夹具结构,其中存储了一个对象 vector 。当我将构建器函数与存储在结构中的 vector 一起使用时,我从构造的 lambda 中得到了奇怪的返回值;当我在结构外部创建对象 vector 时,返回值很好。这是重现这种情况的示例代码:

#include <iostream>
#include <vector>

class LambdaBuilder {
double m_;
double b_;
protected:
// lambda member
std::function<double(double)> lambda_function
= [this](double x){return m_*x+b_;};
public:
// sums the lambda member in a vector of LambdaBuilders
LambdaBuilder(double m, double b) : m_(m), b_(b){};

static std::function<double(double)>
buildFunction(const std::vector<LambdaBuilder> &lambdas){
auto ret = [&lambdas](double x){
double val = 0;
for (auto & lam : lambdas)
val += lam.lambda_function(x);
return val;
};
return ret;
}
};

// constructs and stores a vector of LambdaBuilders
struct Fixture{
std::vector<LambdaBuilder> lambdas;
Fixture(){
LambdaBuilder lambda_0(1,2);
lambdas.push_back(lambda_0);
}
};

int main(int argc, const char * argv[])
{
Fixture fixture;
auto built_function_fixture = LambdaBuilder::buildFunction(fixture.lambdas);

LambdaBuilder lambda_0(1,2);
std::vector<LambdaBuilder> lambdas = {lambda_0};
auto built_function_vector = LambdaBuilder::buildFunction(lambdas);

std::cout << "Function from Feature fixture: "
<< built_function_fixture(5) << std::endl;
std::cout << "Function from Feature vector: "
<< built_function_vector(5) << std::endl;
std::cout << "Should be: " << 1*5 + 2 << std::endl;

return 0;
}

代码输出

Function from Feature struct: 3.47661e-309
Function from Feature vector: 7
Should be: 7
Program ended with exit code: 0

我对 C++11 有点陌生,我不太确定是什么导致了夹具的奇怪结果。

最佳答案

捕获 this 的 lambda 可以被认为具有指针成员。当您复制该 lambda 时,您也复制了指针。

class my_lambda
{
private:
LambdaBuilder* that;
public:
double operator()(double x) const
{ return that->m_*x+that->b_; }
};

此 lambda 具有指针语义。因此,LambdaBuilder 也没有值语义:

class LambdaBuilder {
double m_;
double b_;
protected:
// "lambda member"
std::function<double(double)> lambda_function
= [this](double x){return m_*x+b_;};
public:
// sums the lambda member in a vector of LambdaBuilders
LambdaBuilder(double m, double b) : m_(m), b_(b){};
LambdaBuilder(LambdaBuilder const&) = default;
};

默认复制构造函数将执行成员复制。 std::function 成员的拷贝将复制 lambda。复制的 lambda 指向捕获的 this 的指针仍然引用源对象,而不是目标 LambdaBuilder

因此,当复制 LambdaBuilder 时,您会创建一个间接指向前者的新 LambdaBuilder:

struct Fixture{
std::vector<LambdaBuilder> lambdas;
Fixture(){
LambdaBuilder lambda_0(1,2); // original object
lambdas.push_back(lambda_0); // create a copy referring to `lambda_0`
}
};

这当然很危险,并且会导致 UB,因为 lambda_0 在使用 vector 中的 lambda 之前超出范围。我在评论中建议的“解决方法”碰巧有效,因为 vector 足够大,从未被复制等。它仍然非常危险。


解决方案取决于您希望通过 protected 成员实现的目标。

关于当函数是从存储在夹具结构中的对象构建时,C++ Lambda 构建静态函数返回意外值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24681184/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com