首页 > 解决方案 > 包含 std::function 回调的多个包装器的 std::vector 不起作用

问题描述

我正在编写一个MyTest包含用于存储回调的 std::function<> 的包装器。包装器包含在testsshared_ptr<> 的 std::vector 中。emplace_back 向量工作中的单个包装器,即可以触发 std::function 回调。如果向量中有两个对象,则只有最后一个对象回调有效。

这是我的课程:

typedef function<void(const uint64_t &)> CallBackFunc_t;

class MyWheel
{
private:
    class test
    {
    private:
        const CallBackFunc_t &callback;
    public:
        test(const CallBackFunc_t &cb);
        bool work();
    };

public:
    vector<shared_ptr<test>> tests;
    int addTest(const CallBackFunc_t &test_callback);
    void spin(void);

};


class MyTest
{
private:
    int handle = -1;
    MyWheel &wheel;
public:
    MyTest(MyWheel &whl);
    int setCallback(const CallBackFunc_t &callback);
};

和来源。

MyWheel::test::test(const CallBackFunc_t &cb) : callback(cb)
{

}

bool MyWheel::test::work()
{
    callback(0);
    return true;
}

int MyWheel::addTest(const CallBackFunc_t &test_callback)
{
    tests.emplace_back(new test(test_callback));
    return (int)(test.size()-1);
}

void MyWheel::spin(void)
{
    for(vector<shared_ptr<test>>::iterator test = tests.begin(); test != tests.end(); ++test)
    {
       (*test)->work();
    }
}

MyTest::MyTest(MyWheel &whl) : wheel(whl)
{

};

int MyTest::setCallback(const CallBackFunc_t &callback)
{
    if(handle < 0)
    {
        handle = wheel.addTest(callback);
    }
    return handle;
}

用法:


MyWheel wh;
MyTest t1(wh);
MyTest t2(wh);

t1.setCallback([&](const uint64_t &e) {
   cout <<"1\r\n";
});

t2.setCallback([&](const uint64_t &e) {
   cout <<"2\r\n";
});

while(true)
{
   wh.spin();
}

我希望在运行时打印“1”和“2”,但只有“2”是......我做错了什么?

标签: c++c++11

解决方案


您需要通过副本存储回调:

class test
{
private:
    CallBackFunc_t callback; // <---- make a copy of callback
public:
    test(const CallBackFunc_t &cb);
    bool work();
};

现在您有未定义的行为,因为您正在存储对回调的引用,该回调在此表达式的末尾被销毁:

t1.setCallback([&](const uint64_t &e) {
   cout <<"1\r\n";
}); // it causes dangling reference

如果您想保留对内部回调的引用,test您需要在调用之前将它们创建为左值setCallback

std::function<void (const uint64_t& )> callback1 = [](const uint64_t &e)  {
   cout <<"1\r\n";
};
t1.setCallback(callback1);

std::function<void (const uint64_t& )> callback2 = [](const uint64_t &e)  {
   cout <<"2\r\n";
};
t2.setCallback(callback2);

推荐阅读