powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / создание std::function<> из лямбды с захваченной moveableonly переменной
20 сообщений из 20, страница 1 из 1
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39204627
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
че-то я не допер.. как сделать так, чтобы она заработала?

вот тестовый код
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
#include <future>
#include <functional>


class some{
public:
    some(){}
    some(const some&) =delete ;
    some(some&& )=default ;
    some& operator = (const some&) = delete;
    some& operator = (some&&) = default ;
};

int main(int argc, char** argv)
{
    some ss;
    auto src_fnc = [ss=std::move(ss)](){return 10;};
    std::function<int ()> ll ( std::move(src_fnc) );
    std::function<int ()> other_ll = std::move(ll);
    return 0;
}

а вот ошибки
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
g++ -std=c++14 lambda.cpp
In file included from /usr/include/c++/5/future:38:0,
                 from lambda.cpp:1:
/usr/include/c++/5/functional: In instantiation of ‘static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::true_type) [with _Functor = main(int, char**)::<lambda()>; std::true_type = std::integral_constant<bool, true>]’:
/usr/include/c++/5/functional:1746:16:   required from ‘static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = main(int, char**)::<lambda()>]’
/usr/include/c++/5/functional:2256:19:   required from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = main(int, char**)::<lambda()>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = int; _ArgTypes = {}]’
lambda.cpp:18:48:   required from here
/usr/include/c++/5/functional:1702:4: error: use of deleted function ‘main(int, char**)::<lambda()>::<lambda>(const main(int, char**)::<lambda()>&)’
    new (__dest._M_access()) _Functor(__source._M_access<_Functor>());
    ^
lambda.cpp:17:34: note: ‘main(int, char**)::<lambda()>::<lambda>(const main(int, char**)::<lambda()>&)’ is implicitly deleted because the default definition would be ill-formed:
  auto src_fnc = [ss=std::move(ss)](){return 10;};
                                  ^
lambda.cpp:17:34: error: use of deleted function ‘some::some(const some&)’
lambda.cpp:8:2: note: declared here
  some(const some&) =delete ;
  ^


выходит что у лямбды нет конструктора копирования, а у std::function - есть, и он пытается собраться, но это разумеется не получается.

но компилятор показывает ошибку в другом месте - в том, где все нормально. если закоментировать создание std::function то код прекрасно компилится.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39204642
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexy_black,

Внутри лямбда хранит захваченные значения в виде полей класса.
std::function внутри хранит саму лямбду.

Условно:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
class Lambda {
   Captured cap;
};

class Function {
  Lambda lam;
};



Для того чтобы сохранить лямбду в свое внутреннее поле function копирует ее. При этом рекурсивно копируются и ее поля. Поэтому если в лямбде хранится захваченное значение для которого копирование отключено, то вся эта конструкция не скомпилируется.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39204644
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Т.е. другими словами у этой конкретной лямбды нет конструктора копирования, потому что его нет у захваченного выражения.
А вообще у лямбд конечно есть к-тор копирования )
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39204865
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
http://stackoverflow.com/questions/20843271/passing-a-non-copyable-closure-object-to-stdfunction-parameter

оказалось я не первый кто об это вспоткнулся :)
я так понял, что у лямбды пропадает конструктор копирования если у одного из замыканий его нет (как указал Anatoly Moskovsky) а вот std::function - у неё есть конструктор копирования, и его не отключают если объект не копируемый.. короче либо писать свою noncopyable_function либо использовать что-нибудь из ответов..


я подумал что эту проблему можно решить написав свою функцию и ипспользовать std::is_copy_constructible и std::is_copy_assignable , но похоже так нельзя сделать - это будут разные классы, и какой-нибдуь std::vector<my_super_function<void()>> не сможет держать и копируемые и некопируемые функторы..
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205179
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexy_black,

Вообще перемещение в лямбды выглядит сомнительным по безопасности, если вы их потом пытаетесь копировать эту лямбду в несколько других лямбд. Валидной останется только одна копия, а остальные будут видеть пустой объект.

Используйте shared_ptr вместо стекового объекта, который вы захватываете перемещением.
Это решит и проблему с компиляцией и можно будет создавать сколько угодно равноценных копий лямбды.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205201
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskyalexy_black,

Вообще перемещение в лямбды выглядит сомнительным по безопасности, если вы их потом пытаетесь копировать эту лямбду в несколько других лямбд. Валидной останется только одна копия, а остальные будут видеть пустой объект.

Используйте shared_ptr вместо стекового объекта, который вы захватываете перемещением.
Это решит и проблему с компиляцией и можно будет создавать сколько угодно равноценных копий лямбды.лямбду в лямбду копировать? это зачем и как?

да, shared_ptr - выход. но не хочется для этого выделять память. это нужно системный вызов делать.. там есть такой предложение:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
	template<typename T>
	struct fake_copyable {
		fake_copyable(T&& t) : target(std::forward<T>(t)) {}
		fake_copyable(fake_copyable&& )=default ;
		fake_copyable(const fake_copyable&) {assert(false);}
		template<typename... Args>
		auto operator()(Args&&... a) { return target(std::forward<Args>(a)...); }

		T target ;
	};

только там в конструкторе копирования исключение, а я асерт сделал - так удобнее (когда в дебаге прога свалится, узнать где). если код можно протестить хорошо - все варианты использования - то все гуд. если нельзя так протестить то наверное лучше сделать с shared_ptr .
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205235
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexy_blackлямбду в лямбду копировать? это зачем и как?
В function.

alexy_blackда, shared_ptr - выход. но не хочется для этого выделять память. это нужно системный вызов делать
Не нужно. Вы путаете.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205395
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky,

shared_ptr выделяет память, там оператор new - malloc (правда я реализацию смотрел, но по-другому как?) . создание переменной в куче более дорого чем на стеке.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205420
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexy_black,

malloc - это не системный вызов.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205434
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovskymalloc - это не системный вызов. http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html posix однако..

вобще выделяет память система. то есть её "просят" выделить память, а потом, когда это область больше не нужна её возращают. память должна выделять система - она контролирует чтобы опреративки хватило.. а напрямую нельзя обращаться к памяти - то есть опять же система должна помнить где она этот кусок предоставила.

стек же обычно выделяется один раз - большой кусок, а потом этим куском пользуются. потом он может быть расширен, тоже вроде системным вызовом, но это все равно будет всего один вызов в исключительной ситуации, а не вызов на каждую перменную на стеке.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205440
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Глубоко не вникал в казуистику перемещений, поэтому есть непонятный момент как может быть перемещен локальный объект. Как это реализует компилятор? Если по простому то перемещение на уровне асма это смена указателей, т.е. данные объекта на том же месте остаются. Но как они могу остаться на том же месте если это локальная переменная на стэке? При выходе из функции стэк освободился, но "свободный" кусочек остался занят перемещенной переменной? Ерунда какая-то
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205447
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Об этом речь?
https://en.wikipedia.org/wiki/Return_value_optimization

А это добавка к фокусам компилятора
https://en.wikipedia.org/wiki/Call_stack#STACK-UNWINDING
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205448
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexy_blackAnatoly Moskovskymalloc - это не системный вызов. http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html posix однако..

Тут нигде не сказано что malloc это системный вызов.

Вы путаете рантайм С и системные вызовы.
Стандартная функция рантайма С malloc выделяет память из кучи (заранее выделенной у системы области памяти процесса).
Когда куча заканчивается, malloc выделяет у системы следующий участок кучи (обычно через системный вызов mmap или его аналог в других ОС).
Для больших размеров объектов, malloc может сразу у системы память вызывать. Но это надо большие массивы выделять. А у вас естественно через кучу выделяется, поэтому никакие системные вызовы не замедляют работу, т.к. вызываются слишком редко.

При этом я не спорю с тем что динамическое создание объекта чуть медленнее чем стековое. Но не настолько, чтобы городить вот эти костыли с фейковыми конструкторами.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205458
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglDima T,

Об этом речь?
https://en.wikipedia.org/wiki/Return_value_optimization

А это добавка к фокусам компилятора
https://en.wikipedia.org/wiki/Call_stack#STACK-UNWINDING
Не об этом. Вот у alexy_black код 18996721
Код: plaintext
1.
2.
3.
4.
auth::task_queue::task_queue() : thread_([this](){
...
				std::list<std::function<void ()>> tasks;
				tasks.swap(tasks_);


где tasks_ свойство класса, а tasks локальная переменная, т.е. область видимости совсем другая.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205462
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexy_blackAnatoly Moskovskymalloc - это не системный вызов. http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html posix однако..

вобще выделяет память система. то есть её "просят" выделить память, а потом, когда это область больше не нужна её возращают. память должна выделять система - она контро.

Ты линк на malloc дал неправильный ВОТ правильный.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205475
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Видимо захват лямбдой this дает нужную область видимости. А потом _внутри_ листа подменяются указатели.

По поводу копирования - есть еще такое
https://en.wikipedia.org/wiki/Copy_elision

Только мне кажется, что так писать код не очень хорошо, как написал Алексей - он и сам то не разберется =)
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205486
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglDima T,

Видимо захват лямбдой this дает нужную область видимости. А потом _внутри_ листа подменяются указатели.

По поводу копирования - есть еще такое
https://en.wikipedia.org/wiki/Copy_elision

Только мне кажется, что так писать код не очень хорошо, как написал Алексей - он и сам то не разберется =)
Написано как раз понятно, просто и очевидно, но как оно в итоге будет реализовано компилятором - непонятно. ИМХУ Надо просто затестить производительность, только надо придумать как тестить.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39205608
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TГлубоко не вникал в казуистику перемещений, поэтому есть непонятный момент как может быть перемещен локальный объект. Как это реализует компилятор? Если по простому то перемещение на уровне асма это смена указателей, т.е. данные объекта на том же месте остаются. Но как они могу остаться на том же месте если это локальная переменная на стэке? При выходе из функции стэк освободился, но "свободный" кусочек остался занят перемещенной переменной? Ерунда какая-то
Во-первых класс должен поддерживать перемещение и сам его реализовывать (когда возможно, компилятор генерирует этот код).
Во-вторых, обычно перемещение реализуется как рекурсивный swap всех полей класса.
Т.е. сам объект остается, а его содержимое меняется местами с содержимым конечного объекта.
Так что неважно где расположены объекты.
Такая оптимизация конечно имеет смысл, только для классов с полями указывающими на динамическую память, и имеет цель избежать при копировании выделения и копирования памяти.
Например хорошие кандидаты - std::vector, std::string.
Плохие кандидаты: std::array, std::tuple - так как вся память находится в самом объекте, и повторное создание с нуля через стандартный к-тор копирования будет в 2 раза быстрее перемещения.
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39206689
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tкак оно в итоге будет реализовано компилятором - непонятно. ИМХУ Надо просто затестить производительность, только надо придумать как тестить.
Код: 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.
#include <iostream>
#include <string>
#include <vector>
#include <list>


const std::size_t cycles = 10000000 ;
using test_type = std::vector<int>;

int main(int argc, char* argv[])
{
    test_type vec_from(cycles,999999);

    test_type vec_to;
    std::cout << "begin swap" << std::endl;
    vec_to.swap(vec_from);
    std::cout << "end swap" << std::endl;

    std::cout << "begin copy" << std::endl;
    std::copy(vec_to.begin(),vec_to.end(),std::back_inserter(vec_from));
    std::cout << "end copy" << std::endl;

    return 0;
}

вот так что ли? тут все понятно и на глаз :) вектор кстати оказался гараздо быстрее (в строке using можно менять vector -> list ... ), что и понятно, ведь это просто массив, а list - это структуры, которые еще и на соседей указатели держат. но во обоих случаях время на свап было мнгновенным, а на copy огромным (на вектор я еще пару нулей добавил, а вот лист такого не выдержал - израсходовал все память и был killed) .
...
Рейтинг: 0 / 0
создание std::function<> из лямбды с захваченной moveableonly переменной
    #39206691
alexy_black
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
по поводу перемещения: не думаю что есть смысл поды перемещать.. то етсь они навеное в любом случаи копируются. а вот если класс содержит указатели или какие-нибудь дескрипторы и тому подобное, то задача пермещения - просто оставить объект в таком состоянии, чтобы он мог уничтожится без проблем.

где-то прочитал: "семантика перемещения - это просто способ сказать, что объект нам больше не нужен". имхо очень доступное объяснение. то есть если вызван констрктор или опрератор перемещения, то это значит, что другой объект будет уничтожен сразу после того как функция отработает и нигде не будет использоваться. а как этим воспользоваться решает программист. если он там сделает такой же конструктор как и констурктор копирования, то ничего не изменится по сравнения с копированием.
...
Рейтинг: 0 / 0
20 сообщений из 20, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / создание std::function<> из лямбды с захваченной moveableonly переменной
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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