将unique_ptr引用传递给boost::bind?

7

我正在使用 CentOS 6.6 (gcc 4.4.7) 并且使用 Boost.Asio (1.41) 进行开发。当 io_service 开始运行时,我希望它调用管理对象 m 中的成员函数 run()。我尝试编译的代码如下:

#include <memory>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

boost::asio::io_service io;
std::unique_ptr<manager> m;
m = std::make_unique<manager>;
io.post(boost::bind(&manager::run, &m));

gcc在包含以下内容的boost::bind语句上出现了错误:

/usr/include/boost/bind/mem_fn_template.hpp:40: error: pointer to
member type ‘void (manager::)()’ incompatible with object type
‘std::unique_ptr<manager, std::default_delete<manager> >’

我在这里想做什么?

管理对象只知道计时器;稍后将添加一个知道io_service的单独对象到其构造函数中。但是,manager::run() 的想法是创建一组初始计时器来引导系统。

澄清:

我的想法是外部代码管理m的生命周期,并且下一个语句将是io.run()。当io.run()返回时,外部代码将销毁m。因此,将原始引用传递给io是合适的。但我是现代C++的新手,可能完全错误。


你不需要传递任何类型的引用到 bind 函数 -- 你需要传递一个普通指针给一个独占指针。但是独占指针必须是唯一的,而在你的代码中,当 post 函数返回时,会有两个指向同一个对象的独占指针 -- 一个在 bind 中,另一个在 m 中。这显然是不正确的。也许你想要使用 boost::bind (&manager::run, std::move(m)) - David Schwartz
boost::bind 不知道如何解开 unique_ptr,你需要传递一个 manager * (m.get()) 或者一个 manager 实例 (*m)(第二个会复制 m 指向的对象)。而且我很难相信你正在使用 gcc4.4.7;那个编译器甚至不理解 -std=c++11,更别说 std::make_unique 这个 C++14 的新增特性了。 - Praetorian
gcc 4.4.7有-std=gnu++0x,而对于make_unique,我抓取了STL的建议 - Andreas Yankopolus
1个回答

5
你需要使用C++-14和广义lambda捕获才能使其工作--你需要将unique指针移动到lambda中。相反,只需使用shared_ptr,这是std::bind本地理解的:
std::shared_ptr<manager> m;
m = std::make_shared<manager>();
io.post(std::bind(&manager::run, std::move(m)));
< p > std::move 是可选的,但确保在不需要时 m 不会保留管理器。


我觉得这样做很不好,至少在我当前对unique指针和shared指针的影响有了解之前是这样。io将不负责m的生命周期。按照程序的运行方式,m将在io.run()运行后(紧接着io.post())清除。make_shared()会给读者留下错误的印象吗? - Andreas Yankopolus
1
@AndreasYankopolus m 变量将被清理,但是 bind 将通过值捕获共享指针,只要 bind 存在,它就会保留管理器,直到其执行完成。 - David Schwartz
1
m保留为unique_ptr,并将绑定语句更改为:boost::bind(&manager::run, m.get())是错误的吗? - Andreas Yankopolus
1
@AndreasYankopolus 是的,因为这样管理器可能会被过早删除(一旦 m 超出范围)。你需要使用 bind 来使管理器保持活动状态,这需要按值捕获某些东西来保持管理器存在。 - David Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接