C++ boost 回调返回数据

C++ boost callback returning data

提问人:Paul 提问时间:8/17/2023 更新时间:8/17/2023 访问量:52

问:

我正在努力从回调中获取数据(而不是向回调发送参数)。我可以在没有数据的情况下触发回调,但希望能得到一些关于我所缺少内容的指导。如上所述,它可以在不返回数据的情况下工作,将相邻的注释掉的行换成我的尝试作为返回数据(所以错误很可能在那里)。

#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <map>
#include <string>

typedef boost::function<void()> callback;       
//typedef boost::function<void(std::string)> callback;    // With return argument

class B
{
public:
    //typedef boost::shared_ptr<const printer> SharedConst;

    B(boost::asio::io_service& io, std::string name_, int target_, callback call_)
    : timer_(io, boost::posix_time::seconds(1)),
      count(1), target(target_), name(name_), call(call_)
    {
        timer_.async_wait(boost::bind(&B::print, this));
    }
    
    ~B()
    {
        std::cout << "Final count is " << count << "\n";
    }
 
    void print()
    {
        if (count < target)
        {
            std::cout << name << " : " << count << "\n";
            ++count;

            timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
            timer_.async_wait(boost::bind(&B::print, this));
        } 
        else {
            call();
            //call(name);
        }
    }

private:
    callback call;
    boost::asio::deadline_timer timer_;
    int count;
    int target;
    std::string name;
};

class A {
private:
    std::map<std::string, B*> jobs;
    boost::asio::io_service io;

public:
    void acceptResult()
    //void acceptResult(std::string jobID_)
    {
        std::cout << "acceptResult" << std::endl; 
        //std::cout << "acceptResult from job : " << jobID_<< std::endl; 
        //free(jobs.at(jobID_));   
        //auto it = jobs.find(jobID_);
        //jobs.erase(it);
    }

    void newJob(std::string jobID_, unsigned int target)
    {
        B *b = new B(io, jobID_, target, boost::bind(&A::acceptResult, this));
        jobs.insert({jobID_, b});
    }

    void run()
    {
        io.run();
    }
};

int main()
{
    A a;
    a.newJob("j1", 5);
    a.newJob("j2", 3);

    a.run();

    return 0;
}

输出(不返回值):

j1 : 1
j2 : 1
j1 : 2
j2 : 2
j1 : 3
acceptResult
j1 : 4
acceptResult

提前致谢,保罗。

C++ Boost 回调

评论

0赞 Ted Lyngmo 8/17/2023
您使用的是哪个 C++ 版本?如果您使用的是 C++11 或更高版本,则可以通过使用 lambda 等来简化这一点。
0赞 Paul 8/17/2023
我将 cmake 设置为 20,很高兴尝试任何新事物 =)。我看到的最后一个 lambda 示例看起来像一只猫脸先掉进了键盘的括号部分......您能举个例子吗?
1赞 Ted Lyngmo 8/17/2023
确定。我无法让 boost 接受 lambda,但至少是重要的 () 使用隐式占位符 () 的已弃用功能(或类似的东西)。在用 lambda 替换它后,我包括了其余的 s。我需要上床睡觉,所以我不能给你一个完整的答案,但我所做的事情是这样的,但这是结果async_waitboost::bind(&A::acceptResult, this)_1<boost/bind/bind.hpp>bind
1赞 Ted Lyngmo 8/17/2023
...或者,如果您真的想自动启动作业,这可能是一种替代方法。
0赞 Paul 8/17/2023
谢谢泰德!我还没来得及寻找那个绑定警告,你也得到了=)。我很感激你清理我的例子。我学到了一些东西=)。

答:

2赞 sehe 8/17/2023 #1

首先,我们来清理一些问题:

  • 初始化顺序 ( 之后callbackname)
  • 内存泄漏(应管理作业生存期):jobs
  • 销毁顺序(应该在 AFTERiojobs)

我可能修复了更多,但我忘记了: Live On Coliru

j1 : 1
j2 : 1
j1 : 2
j2 : 2
j1 : 3
acceptResult
j1 : 4
acceptResult
Final count is 3
Final count is 5

问题

取消注释“问题”行,我注意到您忘记了参数的占位符:bindname

boost::bind(&A::acceptResult, this, boost::placeholders::_1)

就这样!由于我的选择,不需要复杂(而且不是例外安全)的舞蹈。哦,更不用说 / 是不正确的!unique_ptrfreenewdelete

void acceptResult(std::string jobID_) {
    std::cout << "acceptResult from job : " << jobID_<< std::endl;
    jobs.erase(jobID_);
}

在 Coliru 上直播

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <map>
#include <string>

using callback = std::function<void(std::string)>; // With return argument

class B {
  public:
    B(boost::asio::io_service& io, std::string name_, int target_, callback call_)
        : timer_(io, boost::posix_time::seconds(1))
        , count(1)
        , target(target_)
        , name(name_)
        , call(call_) {
        timer_.async_wait(boost::bind(&B::print, this));
    }

    ~B() { std::cout << "Final count is " << count << "\n"; }

    void print() {
        if (count < target) {
            std::cout << name << " : " << count << "\n";
            ++count;

            timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
            timer_.async_wait(boost::bind(&B::print, this));
        } else {
             call(name);
        }
    }

  private:
    boost::asio::deadline_timer timer_;
    int                         count;
    int                         target;
    std::string                 name;
    callback                    call;
};

class A {
  private:
    boost::asio::io_service                   io; // ORDER! destruct last
    std::map<std::string, std::unique_ptr<B>> jobs;

  public:
    void acceptResult(std::string jobID_) {
        std::cout << "acceptResult from job : " << jobID_<< std::endl;
        jobs.erase(jobID_);
    }

    void newJob(std::string jobID_, unsigned int target) {
        jobs.emplace(jobID_,
                     std::make_unique<B>(io, jobID_, target,
                                         boost::bind(&A::acceptResult, this, boost::placeholders::_1)));
    }

    void run() { io.run(); }
};

int main() {
    A a;
    a.newJob("j1", 5);
    a.newJob("j2", 3);

    a.run();
}

指纹

j1 : 1
j2 : 1
j1 : 2
j2 : 2
j1 : 3
acceptResult from job : j2
Final count is 3
j1 : 4
acceptResult from job : j1
Final count is 5

评论

0赞 Paul 8/17/2023
谢谢 sehe,无论是以“原始”非 lambda 方式修复它,因为这仍然困扰着我为什么它是错误的,并修复了我的其他错误。
1赞 Ted Lyngmo 8/17/2023
@Paul这就是我提到的“隐式占位符 (_1) 的弃用功能”。我应该添加它来显示它的去向,但选择了(恕我直言)更简单的 lambda。我也使用 s 作为测试,但得到了一个竞争条件。奇怪。我现在刚刚将它添加到我的代码中,当然它就像一个魅力:-)unique_ptr
0赞 sehe 8/18/2023
@TedLyngmo 您能指出这种“隐式占位符”的文档/示例吗?据我所知,Boost Bind 中从未存在过这样的功能。Boost Lambda/Phoenix 占位符可能存在混淆,甚至与全局命名空间占位符的默认声明混淆,这些占位符最近确实被弃用了(但从来都不是隐式的,只是污染了全局命名空间)。
1赞 Ted Lyngmo 8/18/2023
@sehe我不是从文档中得到的,而是在编译时得到的,但我没有正确记住确切的消息。它是:“声明 Bind 占位符 (_1, _2, ...) 的做法在全局命名空间中已弃用。请使用<boost/bind/bind.hpp>......“ - 所以,不是一回事,不是......
1赞 sehe 8/18/2023
@TedLyngmo不不不,完全诚实。我亲身体会到,在这个网站上做出贡献可能很耗时,而且相对来说吃力不讨好。我知道我从你那里看到了一些深刻的见解,所以我很高兴能够向你提问,并看到你在这个网站上帮助人们。(英语也不是我的第一语言,但老实说,我认为这更多的是关于人们从不表达感谢,或者当它发生时,人们担心的程度还不够!