std::bind теряет ссылку при доставке как ссылка на значение

У меня есть следующий код:

#include <stdio.h>
#include <functional>

template <typename T>
auto callback(T&& func) ->decltype(func())
{
    return func();
}

double test(double& value)
{
    value=value+1.0;
    return value;
}

int main(void)
{
    double t=1.0;
    printf("%f\n",t);
    test(t);
    printf("%f\n",t);
    callback(std::bind(test,t));
    printf("%f\n",t);
}

И это выводит

1.000000
2.000000
2.000000

Что подразумевает callback функция получила копию t вместо ссылки на t, Мне интересно, что случилось, так как для std::bind это должно быть совершенным пересылкой.

2 ответа

Решение

std::bind по умолчанию использует семантику значений. Это нормальное значение по умолчанию, позволяющее безопасно выполнять следующие действия.

int f(double x);

auto fun = std::bind(f, 1.0); // stores a copy, not a reference to a temporary
fun();

Использование семантики значений безопасно: время жизни связанных аргументов становится временем жизни объекта, возвращаемого связью. Использование ссылочной семантики не дает такой гарантии. Таким образом, вы должны быть явными, когда вы хотите ссылочную семантику; если вы попали в беду, то это ваша вина. Для этого вам нужно использовать std::ref:

int main(void)
{
    double t=1.0;
    printf("%f\n",t);
    test(t);
    printf("%f\n",t);
    callback(std::bind(test, std::ref(t)));
    printf("%f\n",t);
}

Этот же протокол используется в других местах стандартной библиотеки, например std::thread конструктор.

std::bind() разработан для семантики значений ( как хорошо объясняет в своем ответе Р. Мартиньо Фернандес) и создает копии внутри. Что вам нужно / хотите это std::ref:

callback(std::bind(test, std::ref(t)));
//                       ^^^^^^^^^^^

std::ref возвращает std::reference_wrapper<> объект, который переносит ссылку на ваш исходный аргумент. Таким образом, reference_wrapper объект вокруг t копируется, а не t сам.

Это позволяет вам выбирать между семантикой значений (предполагается по умолчанию) и семантикой ссылок (которая требует вашего явного вмешательства).

Вот живой пример.

Другие вопросы по тегам