For reasons associated with the circumstances I'm using them in, I declare lambdas in one object, copy them to a second object, and execute them from a static function of a third class.
Ok, it seems my original post was a little short on information, so I've developed a simple app to demonstrate the issue.
// LambdaCaptureTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <memory>
#include <vector>
#include <iostream>
struct LambdaWrapperBase {
virtual ~LambdaWrapperBase() {}
};
template <typename Lambda>
struct LambdaWrapper : public LambdaWrapperBase
{
LambdaWrapper(Lambda lambda) : lambda_(lambda) {}
Lambda& lambda_;
};
struct LambdaCallerBase
{
virtual void executeLambda(LambdaWrapperBase*) = 0;
};
template <typename Lambda>
struct LambdaCaller : public LambdaCallerBase
{
void executeLambda(LambdaWrapperBase* lambda_wrapper_base) override
{
typedef LambdaWrapper<Lambda> LambdaWrapper_t;
LambdaWrapper_t* lambda_wrapper = dynamic_cast<LambdaWrapper_t*>(lambda_wrapper_base);
std::cout << """ << lambda_wrapper->lambda_().c_str() << """ << std::endl;
}
};
std::vector<std::unique_ptr<LambdaWrapperBase> > g_lambda_wrappers;
std::vector<std::unique_ptr<LambdaCallerBase> > g_lambda_callers;
std::string g_tag = "A global Tag";
class CreateLambdas
{
public:
CreateLambdas() : tag_("A member Tag")
{
auto lambda1 = []() -> std::string { return std::string("An immediate tag"); };
addLambda(lambda1);
auto lambda2 = []() -> std::string { return g_tag; };
addLambda(lambda2);
std::string tag = "A Local Tag";
auto lambda3 = [=]() -> std::string { return tag; };
addLambda(lambda3);
auto lambda4 = [this]() -> std::string { return this->tag_; };
addLambda(lambda4);
// These all work as expected
std::cout << """ << lambda1().c_str() << """ << std::endl;
std::cout << """ << lambda2().c_str() << """ << std::endl;
std::cout << """ << lambda3().c_str() << """ << std::endl;
std::cout << """ << lambda4().c_str() << """ << std::endl;
}
template<class F> void addLambda(F method)
{
g_lambda_wrappers.push_back(std::unique_ptr<LambdaWrapperBase>(new LambdaWrapper<F>(method)));
g_lambda_callers.push_back(std::unique_ptr<LambdaCallerBase>(new LambdaCaller<F>()));
}
std::string tag_;
};
int _tmain(int argc, _TCHAR* argv[])
{
CreateLambdas createLambdas;
// This outputs "An immediate tag"
g_lambda_callers[0]->executeLambda(g_lambda_wrappers[0].get());
// This outputs "A global tag"
g_lambda_callers[1]->executeLambda(g_lambda_wrappers[1].get());
// this crashes. If I look at that point in the debugger,
// then the local variable "tag" says "Error reading characters of string"
g_lambda_callers[2]->executeLambda(g_lambda_wrappers[2].get());
// this crashes. If I look at it in the debugger at the crash point,
// then "this" is 0xcccccccc - i.e. invalid
g_lambda_callers[3]->executeLambda(g_lambda_wrappers[3].get());
return 0;
}
Aucun commentaire:
Enregistrer un commentaire