Связать с 1 вызовом копии Ctor - PullRequest
3 голосов
/ 29 января 2011

Мне нужен отложенный вызов некоторой функции с аргументами. Иметь следующий тестовый код:

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

struct test
{
    test()
    {
        std::cout << "ctor" << std::endl;
    }

    test& operator=(test const& t)
    {
        std::cout << "operator=" << std::endl;
        return *this;
    }

    test(test const& t)
    {
        std::cout << "copy ctor" << std::endl;
    }

    ~test()
    {
        std::cout << "dtor" << std::endl;
    }
};

int foo(test const & t)
{
    return 0;
}

int main()
{
    test t;
    boost::function<int()> f = boost::bind(foo, t);
    f();
    return 0;
}

Вывод:

ctor
copy ctor
copy ctor
copy ctor
copy ctor
dtor
copy ctor
dtor
dtor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
dtor
dtor
dtor
dtor
dtor
dtor
dtor
dtor
dtor

Итак, мы можем увидеть, что копия ctor вызвала 11 раз !!!

Ok. Изменить boost :: bind to std :: bind:

int main()
{
    test t;
    boost::function<int()> f = std::bind(foo, t);
    f();
    return 0;
}

Вывод:

ctor
copy ctor
copy ctor
copy ctor
dtor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
dtor
dtor
dtor
dtor
dtor
dtor
dtor
dtor
dtor

Копирование ctor вызывается 9 раз. Хорошо. Если изменить boost :: function на std :: function copy, ctor будет вызываться только 4 раза. Но это тоже плохое поведение.

Возможно ли это сделать за 1 вызов copy ctor? std :: ref - плохая идея, потому что он может вызываться в другом потоке и т. д.

Извините за мой плохой английский :) Спасибо.

Ответы [ 3 ]

1 голос
/ 29 января 2011

Использование лямбд - хороший ответ.Если по какой-либо причине это не работает для вас, другой возможностью является сохранение результата привязки во что-либо, кроме std :: function:

decltype(std::bind(foo, t)) f = std::bind(foo, t);

или:

auto f = std::bind(foo, t);

В моей системе (clang / libc ++) это выводит:

ctor
copy ctor
dtor
dtor

Хотя ваш пробег может отличаться.

1 голос
/ 29 января 2011

Используйте лямбда-выражение.

int main()
{
    test t;
    std::function<int()> f = [=](){ foo(t); };
    f();
    return 0;
}

Привязка чрезвычайно избыточна из-за невероятной легкости и т. Д. Использования лямбд.Кроме того, вы выполнили компиляцию в режиме Release со всеми оптимизациями, верно?

Вы не получите только один вызов конструктора копирования, потому что сначала вам нужно создать объект функции, а затем назначить этот объект функции вstd :: function.Может быть, это может быть std::move 'd?

Поскольку у вас нет лямбда-выражений и даже привязка создает три копии, вам просто придется вручную написать свой собственный объект функции в этом случае.

0 голосов
/ 29 января 2011

Это немного зависит от времени жизни объекта, который вы хотите связать.

Предполагая, что время жизни этого объекта включает время жизни функтора, просто выполните

int main()
{
    test t;
    boost::function<int()> f( boost::bind(foo, boost::ref( t ) ) );
    f();
    return 0;
}

Возвращает один вызов конструктора и один вызов деструктора. : -)

Приветствия & hth.,

...