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

вот тестовый код
Код: 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
31.03.2016, 00:26
    #39204642
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
alexy_black,

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

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

class Function {
  Lambda lam;
};



Для того чтобы сохранить лямбду в свое внутреннее поле function копирует ее. При этом рекурсивно копируются и ее поля. Поэтому если в лямбде хранится захваченное значение для которого копирование отключено, то вся эта конструкция не скомпилируется.
...
Рейтинг: 0 / 0
31.03.2016, 00:28
    #39204644
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
Т.е. другими словами у этой конкретной лямбды нет конструктора копирования, потому что его нет у захваченного выражения.
А вообще у лямбд конечно есть к-тор копирования )
...
Рейтинг: 0 / 0
31.03.2016, 10:48
    #39204865
alexy_black
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
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
31.03.2016, 14:46
    #39205179
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
alexy_black,

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

Используйте shared_ptr вместо стекового объекта, который вы захватываете перемещением.
Это решит и проблему с компиляцией и можно будет создавать сколько угодно равноценных копий лямбды.
...
Рейтинг: 0 / 0
31.03.2016, 15:13
    #39205201
alexy_black
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
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
31.03.2016, 15:42
    #39205235
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
alexy_blackлямбду в лямбду копировать? это зачем и как?
В function.

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

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

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

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

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

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

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

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

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

При этом я не спорю с тем что динамическое создание объекта чуть медленнее чем стековое. Но не настолько, чтобы городить вот эти костыли с фейковыми конструкторами.
...
Рейтинг: 0 / 0
31.03.2016, 20:03
    #39205458
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
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
31.03.2016, 20:08
    #39205462
YesSql
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
создание std::function<> из лямбды с захваченной moveableonly переменной
alexy_blackAnatoly Moskovskymalloc - это не системный вызов. http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html posix однако..

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

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

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

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

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

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

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

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

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


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