【问题标题】:boost::bind() creates many copies of the argumentboost::bind() 创建参数的许多副本
【发布时间】:2020-08-08 02:19:49
【问题描述】:

我正在使用 boost::bind(Boost 1.64.0 和 gcc 8.3.0)创建一个可调用对象并注意到一个有趣的特性 在绑定构造函数中作为参数传递给可包装函数的对象被复制多次。 即使对象被包裹在 std::move() 中。尽管 std::bind 按预期工作。 示例:

#include <iostream>
#include <boost/bind.hpp>
#include <functional>

class Test
{
public:
    Test()
    {
        std::cout << "Create\n";
    }

    Test(const Test& rhs)
    {
        std::cout << "Copy\n";
    }

    Test(Test&& rhs)
    {
        std::cout << "Move\n";
    }

    ~Test() noexcept
    {

    }
};

void foo(Test& t)
{

}


int main()
{
    Test t;
    auto f = boost::bind(&foo, t);
    f();
}

boost::bind(&foo, t);的输出

Create
Copy
Copy
Copy
Copy
Copy

boost::bind(&foo, std::move(t));的输出

Create
Move
Copy
Copy
Copy
Copy

std::bind(&foo, t) 的输出;

Create
Copy

std::bind(&foo, std::move(t)) 的输出;

Create
Move
  • 为什么 boost 复制这么多次?
  • 将右值作为参数传递给绑定是否正确(在两种实现情况下)?
  • 我是否正确理解 bind 会将对象移动到其上下文并存储它,并在调用 foo 时将其作为左值引用传递?

谢谢!

【问题讨论】:

    标签: c++ c++11 boost


    【解决方案1】:

    这是设计使然。

    为避免这种情况,请避免复制绑定适配器并使用ref

    auto f = boost::bind(&foo, boost::ref(t));
    

    • 为什么 boost 复制这么多次?

    主要是因为你的构造函数不能被省略。将其保留为聚合或微不足道的构造函数,这样就不会发生。

    • 将右值作为参数传递给绑定是否正确(在两种实现情况下)?

    是的,bind 按值捕获参数(除非您使用显式 ref()cref() 来创建 reference_wrappers。)

    • 我是否正确理解 bind 会将对象移动到其上下文并存储它,并在调用 foo 时将其作为左值引用传递?

    Yes


    演示

    Live On Coliru

    #include <boost/bind.hpp>
    #include <functional>
    #include <iostream>
    
    struct Test {
        Test()                       { std::cout << "Create\n"; } 
        Test(const Test& /*unused*/) { std::cout << "Copy\n";   } 
        Test(Test&& /*unused*/)      { std::cout << "Move\n";   } 
        ~Test() noexcept             {                          } 
    };
    
    void foo(Test& /*unused*/) {}
    
    int main() {
        Test t;
        auto f = boost::bind(&foo, boost::ref(t));
        f();
    }
    

    打印:

    Create
    

    【讨论】:

    • 非常感谢。但是如果 t 是一个本地对象,而 f 必须在另一个线程中执行呢?
    • 那么你可以通过移动(bind(&amp;foo, std::move(t)))来减轻至少一个副本,如果你使用带有构造函数的类型而没有奇怪的副作用,编译器会优化其他的。
    • 比较godbolt.org/z/3SVbT2(你可以看到编译器只是发出了所有的operator&lt;&lt;,因为它/has/,但它都是内联的),与godbolt.org/z/dS0bRO相比。
    • 如果你能说明为什么 boost 是这样设计的,那就太好了。对我来说std 正在复制一次。
    • 也许吧。我想说std::bind 不应该被使用。改用语言特性(lambdas),这样编译器就不必通过厚厚的库抽象层进行优化。
    猜你喜欢
    • 2012-03-31
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多