dimanche 19 juin 2016

C++11 Lambda Capture Confusion [on hold]


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