powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Не контачат std::function и std::bind
24 сообщений из 24, страница 1 из 1
Не контачат std::function и std::bind
    #39654520
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Написал такой простой код:

main.cpp:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
#include <functional>
#include <iostream>

namespace
{
    template<typename Type, bool NeedLock = false>
    class MyClass
    {
        Type* p;
    public:

        //disable copying and assignment
        MyClass():
            p(nullptr)
        {}

        MyClass(const MyClass<Type, NeedLock>& Value) = delete;
        MyClass& operator=(const MyClass<Type, NeedLock>& Value) = delete;
        ~MyClass() = default;

        MyClass(MyClass<Type, NeedLock>&& Value):
            p(Value.p)
        {
            Value.p = nullptr;
        }

        MyClass& operator = (MyClass&& Value) noexcept
        {
            p = Value.p;
            Value.p = nullptr;

            return *this;
        }
    };

    template<typename Type, bool NeedLock = false>
    void Write(MyClass<Type, NeedLock>&& foo, string& Data)
    {
        if(NeedLock) std::cout << "Hello, world!" << std::endl;
    }

    template<typename Type, bool NeedLock = false>
    void BigWrite(MyClass<Type, NeedLock>& foo)
    {
        string Data = "fdfdsfdsf";
        std::function<void(void)> Bind = std::bind(&Write<Type, NeedLock>, std::move(foo), Data); //ОШИБКА!!!
    }
}

int main(int argc, char *argv[])
{
    MyClass<int> foo;
    BigWrite<int>(foo);
}



авторошибка: conversion from ‘std::_Bind_helper<false, void (*)({anonymous}::MyClass<int>&&, std::__cxx11::basic_string<char>&), {anonymous}::MyClass<int, false>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type {aka std::_Bind<void (*({anonymous}::MyClass<int>, std::__cxx11::basic_string<char>))({anonymous}::MyClass<int>&&, std::__cxx11::basic_string<char>&)>}’ to non-scalar type ‘std::function<void()>’ requested
std::function<void(void)> Bind = std::bind(&Write<Type, NeedLock>, std::move(foo), Data);
^~~~

В чем проблема?
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654537
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQL,

Наверно bind не умеет передавать rv-ссылки && как есть, и где-то внутри заменяет их на & или вообще на копии объекта.
Замените && на &, а std::move в строке с bind на std::ref. (И для Data тоже надо std::ref, кстати, либо убрать ссылку из типа аргумента)
Типа этого:
Код: plaintext
1.
std::bind(&Write<Type, NeedLock>, std::ref(foo), std::ref(Data))


А если вам надо именно перемещать foo то используте shared_ptr

PS. Думаю что и с rv-ссылками можно извратиться и придумать как, но зачем...
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654539
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyAlekseySQL,

Наверно bind не умеет передавать rv-ссылки && как есть, и где-то внутри заменяет их на & или вообще на копии объекта.
Замените && на &, а std::move в строке с bind на std::ref. (И для Data тоже надо std::ref, кстати, либо убрать ссылку из типа аргумента)
Типа этого:
Код: plaintext
1.
std::bind(&Write<Type, NeedLock>, std::ref(foo), std::ref(Data))


А если вам надо именно перемещать foo то используте shared_ptr

PS. Думаю что и с rv-ссылками можно извратиться и придумать как, но зачем...

Документация говорит другое:
авторАргументы для связывания будут скопированы или перемещены, и никогда не передаются по ссылке, если только не завернуты в std::ref или std::cref.

К тому же у меня уже есть рабочий код, в котором bind принимает перемещенный unique_ptr (я им обернул iostream, чтобы при возникновении исключения файл корректно закрылся).
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654714
Фотография OoCc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQLAnatoly MoskovskyAlekseySQL,

Наверно bind не умеет передавать rv-ссылки && как есть, и где-то внутри заменяет их на & или вообще на копии объекта.
Замените && на &, а std::move в строке с bind на std::ref. (И для Data тоже надо std::ref, кстати, либо убрать ссылку из типа аргумента)
Типа этого:
Код: plaintext
1.
std::bind(&Write<Type, NeedLock>, std::ref(foo), std::ref(Data))


А если вам надо именно перемещать foo то используте shared_ptr

PS. Думаю что и с rv-ссылками можно извратиться и придумать как, но зачем...

Документация говорит другое:
авторАргументы для связывания будут скопированы или перемещены, и никогда не передаются по ссылке, если только не завернуты в std::ref или std::cref.

К тому же у меня уже есть рабочий код, в котором bind принимает перемещенный unique_ptr (я им обернул iostream, чтобы при возникновении исключения файл корректно закрылся).
bind обьект может вызываться больше одного раза. Поэтому передача ему rv аргумента бессмысленна. Потому он их и не берёт. Ты можешь сконструировать bind обьект с rv аргументом но не сможешь его исполнить по причине описанной в первом предложении.

В твоём "работающем" коде нет исполнения bind обьекта с rv аргументом.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654716
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovsky,
К сожалению, использовать ссылки не получится: у меня происходит итерация по циклу с многократным заполнением / освобождением вспомогательного массива, который через бинды передается для асинхронной записи на диск. Если я передам ссылку на обертку массива, то перейдя к записям нового клиента я очищу массив и заполню его новыми данными, т.е. по этой ссылке будут лежать уже другие записи...

Так что нужно либо передавать по значению (что очень плохо при работе с массивами), либо перемещать...
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654724
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
OoCcbind обьект может вызываться больше одного раза. Поэтому передача ему rv аргумента бессмысленна. Потому он их и не берёт. Ты можешь сконструировать bind обьект с rv аргументом но не сможешь его исполнить по причине описанной в первом предложении.

В твоём "работающем" коде нет исполнения bind обьекта с rv аргументом.

Возможно вы правы. Заглянул в свой "работающий" код:
Код: plaintext
1.
2.
3.
4.
5.
6.
void AsyncExecuteDeleteProcedureOfUniquePtr(const variativeData& Settings,
                                                uptr_Type&& File)
{
std::function<void(void)>&& Bind = std::bind(File.get_deleter(), File.release());
...
}



Другими словами из unique_ptr я выдергивал сырой указатель и функцию удаления объекта и именно их сохранял в бинде. Так сказать, "раздербанивал" unique_ptr для его помещения в бинд.

Хотя мне этот подход кажется неправильным: программист для того и нужен, чтобы следить за логикой работы, и если появится ошибка повторного перемещения объекта, то за разбирательства в таких ошибках он и получает свой хлеб.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39654732
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Короче, я запутался в двух деревьях: надо сначала переместить свой массив в функцию (принимая НЕ по правой ссылке), а при создании bind запихнуть либо по значению (поскольку мой объект хранит указатель на выделенную память и весит очень мало), либо использовать cref. Я упростил предыдущий вариант, убрав шаблоны:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
#include <functional>
#include <iostream>
namespace
{
    class MyClass
    {
        int* p;
    public:

        //disable copying and assignment
        MyClass():
            p(nullptr)
        {}

        MyClass(const MyClass& Value) = delete;
        MyClass& operator=(const MyClass& Value) = delete;
        ~MyClass() = default;

        MyClass(MyClass&& Value):
            p(Value.p)
        {
            Value.p = nullptr;
        }

        MyClass& operator = (MyClass&& Value) noexcept
        {
            p = Value.p;
            Value.p = nullptr;

            return *this;
        }
    };

    void Write(const MyClass& foo) //приняли foo по ссылке
    {
        std::cout << "Hello, world!" << std::endl;
    }

    void BigWrite(MyClass foo) //тут foo содержит валидный указатель
    {
        std::function<void(void)> Bind = std::bind(&Write, std::cref(foo));
        Bind();
    }
}

int main(int argc, char *argv[])
{
    MyClass foo;
    BigWrite(std::move(foo)); //теперь здесь foo пустой и его можно опять наполнять данными
}
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39656147
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Продолжу свой диалог :)

В последнем примере допущена логическая ошибка: когда я выхожу из функции BigWrite, то локальная переменная foo уничтожается, и следовательно в bind- е лежит ссылка на мусор. Конечно, в приведенном примере bind до выхода из функции вызывает оператор () и ошибки вроде как нет, но если он будет использоваться для асинхронного выполнения действий (и класться в какую- нибудь коллекцию для последующего выполнения), то подобный подход не сработает. Поэтому в bind надо класть само значение, а не ссылку (не зря разработчики в bind все принимают по значению).
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39656166
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Переделал для сохранения в bind-е самого значения, но получаю ошибку (MyClass не изменен):

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
namespace
{
    class MyClass
    {
        int* p;
    public:

        //disable copying and assignment
        MyClass():
            p(nullptr)
        {}

        MyClass(const MyClass& Value) = delete;
        MyClass& operator=(const MyClass& Value) = delete;
        ~MyClass() = default;

        MyClass(MyClass&& Value):
            p(Value.p)
        {
            Value.p = nullptr;
        }

        MyClass& operator = (MyClass&& Value) noexcept
        {
            p = Value.p;
            Value.p = nullptr;

            return *this;
        }
    };

void Write(const MyClass& foo) //приняли foo по ссылке
    {
        std::cout << "Hello, world!" << std::endl;
    }

    void BigWrite(const MyClass& foo) //тут foo содержит валидный указатель
    {
        std::function<void(void)> Bind = std::bind(&Write, foo); //ОШИБКА!!!
        //Bind();
    }
}

int main(int argc, char *argv[])
{
    MyClass foo;
    BigWrite(foo);
}



автор/usr/include/c++/7/functional:534: ошибка: no matching function for call to ‘std::tuple<{anonymous}::MyClass>::tuple({anonymous}::MyClass&)’
: _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...)
^

Как лечить?
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39656443
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Выяснил, что проблема в отсутствии конструктора копирования :)

Надо так:
Код: plaintext
1.
 MyClass(const MyClass<Type, NeedLock>& Value) = default;



Но меня все- таки гложат сомнения: неужели никак нельзя в bind переместить объект? Неужели обязательно создавать копию?
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39656476
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQLНо меня все- таки гложат сомнения: неужели никак нельзя в bind переместить объект? Неужели обязательно создавать копию?
Начиная с C++14 можно.
Но не через bind, а через лямбду.

Код: plaintext
1.
2.
3.
std::function<void(void)> Bind = [foo{std::move(foo)}](){
    Write(std::move(foo));
};


Полученный объект будет movable

Гуглите "Generalized lambda capture".

PS. В C++11 тоже можно извратиться в большинстве случаев. Для этого надо написать обертку которая реализует семантику перемещения в конструкторе копирования. Но тут конечно надо аккуратно ))
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39656550
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovsky, спасибо!
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660030
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
OoCcbind обьект может вызываться больше одного раза. Поэтому передача ему rv аргумента бессмысленна. Потому он их и не берёт. Ты можешь сконструировать bind обьект с rv аргументом но не сможешь его исполнить по причине описанной в первом предложении


У Скота Майерса ("Эффективный и современный С++") на 232 странице он в примере перемещает данные в bind, а в последнем абзаце говорится, что при этом в bind создается lvalue- копия перемещенного объекта, которую можно использовать многократно. Короче, я так и не понял почему везде написано, что в bind перемещать можно, а по факту- ошибка.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660170
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQL,

А ещё Мейерс советует не пользоваться bind'ом, отдавая предпочтение лямбдам.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660396
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQLв последнем абзаце говорится, что при этом в bind создается lvalue- копия перемещенного объекта, которую можно использовать многократно. Короче, я так и не понял почему везде написано, что в bind перемещать можно, а по факту- ошибка.
lvalue- копия возможна только если у вас разрешено копирование ))
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660399
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Точнее bind вы сделаете, но скопировать его куда-то не сможете.
Но вызвать не копируя сможете.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660471
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyТочнее bind вы сделаете, но скопировать его куда-то не сможете.
Но вызвать не копируя сможете.

Спасибо, за помощь в поисках. Но ошибка вылазит на строчке создания bind. В последующем (ниже по коду) я этот бинд с помощью std::move перемещаю в очередь для асинхронного выполнения отдельным потоком (не копирую, а именно перемещаю). Так что вроде ваша мысль мимо цели.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660480
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlekseySQL,

Потому что тут копирование:
Код: plaintext
1.
std::function<void(void)> Bind = std::bind ...


А вот ту нет:
Код: plaintext
1.
auto Bind = std::function<void(void)> Bind = std::bind
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660481
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опечаточка была.

А вот тут нет:
Код: plaintext
1.
auto Bind = Bind = std::bind...
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39660482
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Последняя попытка

А вот тут нет:
Код: plaintext
1.
auto Bind = std::bind...
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39661067
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly Moskovsky, а можно подробнее, почему тут
есть копирование:
Код: plaintext
1.
std::function<void(void)> Bind = std::bind ...



, а тут нет ???:
Код: plaintext
1.
auto Bind = std::bind...



Если бы спецификатор auto мог содержать в себе знак ссылки или временной ссылки, то я бы понял, но ведь он содержит только тип... Совсем не понятно.
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39661110
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решил выяснить какие же функции вызываются и написал:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
namespace
{
    class MyClass
    {
        int* p;
    public:

        //disable copying and assignment
        MyClass():
            p(nullptr)
        {
            std::cout << "Create" << std::endl;
        }

        MyClass(const MyClass& Value)
        {
            std::cout << "Copy" << std::endl;
        }

        MyClass& operator=(const MyClass& Value)
        {
             std::cout << "Assignment" << std::endl;
        }

        ~MyClass()
        {
            std::cout << "Destructor" << std::endl;
        }

        MyClass(MyClass&& Value):
            p(Value.p)
        {
            Value.p = nullptr;
            std::cout << "Moving copy" << std::endl;
        }

        MyClass& operator = (MyClass&& Value) noexcept
        {
            p = Value.p;
            Value.p = nullptr;
            std::cout << "Moving assignment" << std::endl;

            return *this;
        }
    };

    void Write(const MyClass& foo)
    {
        std::cout << "Hello, world!" << std::endl;
    }

    void BigWrite(const MyClass& foo) //В КОММЕНТАРИЯХ УКАЗАЛ ВЫВОД
    {
        auto Bind = std::bind(&Write, foo); //Copy
        auto Bind2 = std::bind(&Write, std::move(foo)); //Copy
        std::function<void(void)> Bind3 = std::bind(&Write, foo); //Copy, Moving copy, Destructor
        std::function<void(void)> Bind4 = std::bind(&Write, std::move(foo)); //Copy, Moving copy, Destructor

        Bind(); //Hello, world!

    }//+Destructor на каждый созданный Bind
}

int main(int argc, char *argv[])
{
    MyClass foo; //Create
    BigWrite(foo);
    return 1;
}



Почему спецификатор auto так меняет положение вещей?
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39661136
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решил продолжить эксперименты и получил еще более адов вывод:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
void BigWrite(const MyClass& foo)
{
auto&& Bind = std::move(std::bind(&Write, foo)); //Copy, Destructor
auto Bind2 = std::move(std::bind(&Write, foo)); //Copy, Moving copy, Destructor
std::function<void(void)> Bind3 = std::move(std::bind(&Write, foo)); //Copy, Moving copy, Moving copy, Destructor, Destructor
std::function<void(void)>&& Bind4 = std::move(std::bind(&Write, foo)); //Copy, Moving copy, Moving copy, Destructor, Destructor
}



В первой строчке вызывается деструктор (!!!), и если после этой строки написать Bind(), то в функции Write вместо наполненного объекта foo, мы получаем пустой объект... Похоже разобраться cо странным объектом bind не получится и надо просто уходить на лямбды ...
...
Рейтинг: 0 / 0
Не контачат std::function и std::bind
    #39661230
AlekseySQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А вот лямбда- функции работают хорошо (у меня есть пул задач, у которых есть поле std::function<void(void)>):

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
         std::cout << "___________________________________" << std::endl;
         auto Bind5 = [foo = std::move(foo)]
        {
            Write(foo);
        };

        asyncTask* const CurrentTask5 = new asyncTask(Settings, std::move(Bind5));
        AsyncPool->AddTask(CurrentTask5);
        CurrentTask5->operator ()();
        std::cout << "___________________________________" << std::endl;

        std::function<void(void)> Bind6 = [foo = std::move(foo2)]
        {
            Write(foo);
        };

        asyncTask* const CurrentTask6 = new asyncTask(Settings, std::move(Bind6));
        AsyncPool->AddTask(CurrentTask6);
        CurrentTask6->operator ()();
         std::cout << "___________________________________" << std::endl;




Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
___________________________________
Moving copy
Moving copy
Moving copy
Destructor
Hello, world!
___________________________________
Moving copy
Moving copy
Destructor
Hello, world!
___________________________________

Видно, что если Bind объявлять с помощью std::function<void(void)>, то количество перемещений сокращается.
...
Рейтинг: 0 / 0
24 сообщений из 24, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Не контачат std::function и std::bind
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]