boost :: bind () создает много копий аргумента - PullRequest
1 голос
/ 24 апреля 2020

Я работал с boost :: bind (Boost 1.64.0 и g cc 8.3.0), чтобы создать вызываемый объект, и заметил интересную особенность. Объект, переданный в конструктор bind в качестве аргумента для функции с возможностью переноса, копируется многократно. Даже если объект обернут в 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
  • Почему так многократно повышается копирование?
  • Правильно ли передавать rvalue в качестве аргумента для привязки (в обоих случаях реализации)?
  • Делать Я правильно понимаю, что bind переместит объект в его контекст и сохранит его, а когда вызывается foo, передает его как ссылку lvalue?

Спасибо!

1 Ответ

1 голос
/ 24 апреля 2020

Это специально.

Чтобы избежать этого, избегайте копий адаптера связывания и используйте ref:

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

  • Почему так много копий? раз?

Главным образом из-за того, что ваш конструктор не может быть исключен. Оставьте его агрегатным или тривиальным конструктором, и этого не произойдет.

  • Правильно ли передать rvalue в качестве аргумента для привязки (в обоих случаях реализации)?

Да, привязка захватывает аргументы по значению (если вы не используете явные ref() или cref() для создания reference_wrapper с.)

  • Правильно ли я понимаю, что привязка переместит объект в его контекст и сохранить его, и когда вызывается foo, передает его как ссылку lvalue?

Да


Демо

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
...