std :: function对象失效

时间:2017-11-13 10:31:34

标签: c++11

以下代码根据我的理解不起作用。当Raise  调用handler对象的方法,随机(我假设未初始化的变量)值被打印。我怀疑map::insert中的CreateTests次调用导致某种移动导致this参数无效,提供给std::function提供给EventCoordinator::Register的对象}}。该程序的预期输出将是在控制台中打印的2行,其值为0& 1已打印。有人可以告诉我这里的错误是什么吗?

#include <map>
#include <functional>
#include <vector>
#include <iostream>

class EventCoordinator
{
    using Handler = std::function<void()>;
    using Handlers = std::vector<Handler>;

    std::map<int, Handlers> HandlerMap;

public:

    void Register(const int id, std::function<void()> handler)
    {
        HandlerMap[id].emplace_back(handler);
    }

    void Raise(const int id)
    {
        try {
            auto handlers = HandlerMap.at(id);
            for (const auto& handler : handlers) {
                handler();
            }
        }
        catch (std::exception& e) {
            std::cout << e.what();
        }

    }
};

class test
{
public:
    test() : mId(-1)
    {
        std::cout << "test default constructor\n";
    }
    test(const int id, EventCoordinator& handler) : mId(id)
    {
        handler.Register(mId, std::bind(&test::func, *this));
    }

    void other()
    {
        std::cout << this << '\n';
    }

    void func() const
    {

        std::cout << this <<'\n';
        std::cout << mId << '\n';
    }
    ~test() = default;
    test(const test& other) = default;
    test(test&& other) noexcept = default;
    test& operator=(const test& other) = default;
    test& operator=(test&& other) noexcept = default;
    int mId;
};

std::map<int, test> CreateTests(EventCoordinator& handler)
{
    auto returnMap = std::map<int, test>();
    returnMap.emplace(std::make_pair(0, test(0, handler)));
    returnMap.emplace(std::make_pair(1, test(1, handler)));
    return returnMap;
}


int main(int argc, char** args)
{
    EventCoordinator handler;
    auto ret = CreateTests(handler);
    handler.Raise(0);
    ret[0].other();
    handler.Raise(1);
    ret[1].other();
    std::cin.get();
}

3 个答案:

答案 0 :(得分:1)

在此功能中:

std::map<int, test> CreateTests(EventCoordinator& handler)
{
    auto returnMap = std::map<int, test>();
    returnMap.insert({ 0, test(0, handler)});
    returnMap.insert({ 1, test(1, handler)});
    return returnMap;
}

您创建了两个临时test类。当CreateTests返回时,这些超出了范围。

main()

auto ret = CreateTests(handler);
handler.Raise(0);
handler.Raise(1);
调用

func,访问test::mId,但不再存在,因此值已损坏。

答案 1 :(得分:1)

根据@alain的建议,无法在test对象的构造函数中执行test对象的注册。 register_test类中添加了test方法。以下代码采用初始化的std::map<int,test>对象,并对存储在地图中的对象调用test::register

#include <map>
#include <functional>
#include <vector>
#include <iostream>
#include <memory>

class EventCoordinator
{
    using Handler = std::function<void()>;
    using Handlers = std::vector<Handler>;
    std::map<int, Handlers> HandlerMap;

public:

    void Register(const int id, std::function<void()> handler)
    {
        HandlerMap[id].emplace_back(handler);
    }

    void Raise(const int id)
    {
        try {
            auto handlers = HandlerMap.at(id);
            for (const auto& handler : handlers) {
                handler();
            }
        }
        catch (std::exception& e) {
            std::cout << e.what();
        }
    }
};

class test 
{
    int mId;
public:
    test() : mId(-1)
    {
        std::cout << "test default constructor\n";
    }

    test(const int id) : mId(id)
    {}

    void register_test(EventCoordinator& handler) {
        handler.Register(mId, std::bind(&test::func, this));
    }

    void func() const
    {
        std::cout << mId << '\n';
    }

    ~test() = default;
    test(const test& other) = default;
    test(test&& other) noexcept = default;
    test& operator=(const test& other) = default;
    test& operator=(test&& other) noexcept = default;
};

void RegisterTests(std::map<int,test>& testCollection,EventCoordinator& coordinator)
{
    for (auto& test: testCollection){
        test.second.register_test(coordinator);
    }
}

std::map<int, test> CreateTests(EventCoordinator& coordinator)
{
    auto returnMap = std::map<int, test>();
    returnMap.emplace(std::make_pair(0, test(0)));
    returnMap.emplace(std::make_pair(1, test(1)));
    RegisterTests(returnMap, coordinator);
    return returnMap;
}


int main(int argc, char** args)
{
    EventCoordinator handler;
    auto ret = CreateTests(handler);
    handler.Raise(0);
    handler.Raise(1);
    std::cin.get();
}

答案 2 :(得分:0)

经过几次尝试后,我发现了一个小错误。

Register构造函数中使用Test成员函数时,使用指针this,但是需要引用而不是指针,因此更改this *this我觉得代码运行正常:

 test ( const int id , EventCoordinator& handler ) : mId ( id )
  {
    handler.Register ( mId , std::bind ( &test::func , *this ) );
  }