std :: vector нескольких оболочек, содержащих обратные вызовы std :: function, не работает - PullRequest
0 голосов
/ 13 октября 2019

Я кодирую оболочку MyTest, которая содержит std :: function <>, используемую для хранения обратного вызова. Оболочки содержатся в std :: vector tests of shared_ptr <>. 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» - это ... Что я делаю не так?

Ответы [ 2 ]

1 голос
/ 13 октября 2019

Вам необходимо сохранить обратный вызов по копии:

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, вам нужно создать их как Lvalues ​​перед вызовом 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);
0 голосов
/ 13 октября 2019

Привет rafix07 и спасибо за примеры! Да, это помогло, и добавление & в список захвата позволило получить доступ к переменным, для которых была определена функция обратного вызова.

Т.е.

bool var1 = false;
std::function<void (const uint64_t& )> callback1 = [&](const uint64_t &e)  {
   cout <<"1\r\n";
   var1 = true;
};
t1.setCallback(callback1);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...