强制将对象作为副本传递给接收通用引用的函数

时间:2016-10-26 17:47:10

标签: c++ c++11 lambda stdbind

我试图将本地lambda函数传递给std::bind(用于传递信号的connect函数):

void f()
{
    auto signal_f = [this](int, int) { /* ... */ };

    namespace ph = std::placeholders;
    signal.connect(std::bind(signal_f, ph::_1, ph::_2));
}

但是std::bind的函数参数作为通用引用被接收:

template<class F, class... Args>
/* unspecified */ bind(F&& f, Args&&... args);

因此,由于我的lambda对象是一个命名对象,它作为左值引用传递,但我的lambda对象将在f()存在后被销毁,可能在信号发出时导致内存泄漏。

通过复制传递该对象的最简单方法是什么?

当然,我总能做到这样的事情:

signal.connect(std::bind<std::decay<decltype(signal_f)>::type>
   (signal_f, ph::_1, ph::_2));

其他棘手的方法,但它们太麻烦了,那么,最简​​单的方法是什么?

注意:标准库中是否有任何函数可以创建副本,例如std::make_rvalue(o)std::copy版本的对象而不是容器?

2 个答案:

答案 0 :(得分:4)

如果你阅读std::bind()的文档,你会看到:

  

std::bind的返回类型包含从std::decay<F>::type构建的std::forward<F>(f)类型的成员对象

它没有对signal_f的引用,它持有它的副本。不依赖signal_f的生命周期。唯一的依赖是this的生命周期,signal_f捕获。

请注意:

signal.connect(std::bind<std::decay<decltype(signal_f)>::type>(signal_f, ph::_1, ph::_2));

实际上与此相同(decay没有意义,因为闭包类型不是引用类型):

signal.connect(std::bind<decltype(signal_f)>(signal_f, ph::_1, ph::_2));

实际上与:

相同
signal.connect(std::bind(std::move(signal_f), ph::_1, ph::_2));

你也可以这样做。

答案 1 :(得分:3)

bind实际上并不存储对lambda的引用。所有参数都被复制(如果是左值)或移动(如果是右值)到bind返回的对象中。

当callable通过引用获取其参数时,这就是为什么在将参数传递给std::ref时需要使用bind的原因。