std::shared_ptr и лямбда функции |
Здравствуйте, гость ( Вход | Регистрация )
std::shared_ptr и лямбда функции |
alexy |
22.10.2013, 10:21
Сообщение
#1
|
Студент Группа: Участник Сообщений: 44 Регистрация: 4.8.2010 Пользователь №: 1931 Спасибо сказали: 0 раз(а) Репутация: 0 |
Встолкнулся с такой проблемой. мне нужно передать указатель на объект в несколько лямбда функций, которые будут вызваны позднее из разных потоков. сразу встал вопрос кто уничтожит объект. ну я подумал сначала что засуну его в std::shared_ptr и делов-то. выходит типа такого
теперь я думаю - он вобще когда-нибудь уничтожиться? или будет храниться веки вечные.. |
|
|
Iron Bug |
22.10.2013, 13:25
Сообщение
#2
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
shared_ptr - нет. уничтожается unique_ptr (это бывший auto_ptr). но если он используется в разных потоках, то должен передаваться по значению.
|
|
|
alexy |
23.10.2013, 18:22
Сообщение
#3
|
Студент Группа: Участник Сообщений: 44 Регистрация: 4.8.2010 Пользователь №: 1931 Спасибо сказали: 0 раз(а) Репутация: 0 |
то есть вот так нужно делать?
и тогда уничтожиться? выходит как бы деструктор скопированных переменных никогда не вызовется? если там написать = то будет как бы утечка памяти, так что ли? эта функция post возращает управление сразу, а код этот исполняет потом, когда будет возможно (там мутексы особождаются и все такое). |
|
|
Iron Bug |
23.10.2013, 20:39
Сообщение
#4
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
после исчезновения последнего обращения unique_ptr уничтожит объект, на который он указывает.
его нельзя передавать по указателю, только по значению или ссылке (лучше - константной). иначе весь смысл работы с unique_ptr теряется и нарушается потокобезопасность и разграниченность доступа. с лямбдами всё сложнее. в новом стандарте C++14 обсуждается вопрос апгрейда лямбда-функций, чтобы они напрямую принимали move (см. пункт Lambda generalized capture). но в С++11 это пока не реализовано. а в качестве решения для С++11 можно сделать так:
если я правильно поняла твою задачу обрати внимание на const std::unique_ptr<foo>. это гарантия, чтобы внутри функции твой объект никто не убил. P.S. тут такие кренделя С++11, что можно запутаться Сообщение отредактировал Iron Bug - 23.10.2013, 21:09 |
|
|
Iron Bug |
23.10.2013, 22:04
Сообщение
#5
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
ещё дополнение:
хорошая статья про unique_ptr. |
|
|
alexy |
23.10.2013, 23:29
Сообщение
#6
|
Студент Группа: Участник Сообщений: 44 Регистрация: 4.8.2010 Пользователь №: 1931 Спасибо сказали: 0 раз(а) Репутация: 0 |
если я правильно поняла твою задачу не совсем... в твоем коде указатель используется прямо на месте, то есть любой умный указатель в принцепе подойтед. функция go завершит исполнение и объект уничтожится.. я попробовал передать копии shared_ptr внути go, думал упадет, но результат был тот же - объект также уничтожался по завершении функции go. а мне нужно чтобы эту лямюду "запостить" в поток. этот поток вызовет её уже тогда, когда функция, "запостившая" и создавшая этот объект, закончит выполнение. объект, созданный в функции оператором new должен удалиться тогда, когда завершит исполнение последняя лямбда функция (иначе крах - обратиться к удаленному объекту). сами объекты потокобезопасные.. P.S. тут такие кренделя С++11, что можно запутаться да уж.. ногу сломаешь )) да, там в стандарте ничего не описанно. на сколько я понял, move нужна чтобы передать управление указателем в эту лямбду.. то есть лямбда завершается и объект уничтожается. но мне не подходит - у меня несколько лямбд, кто будет последней не знаю т.к. они в разных потоках. а std::bind я так понимаю уничтожает привязанные боъекты тогда, когад уничтожается объект, возращаенной это функцией, так? |
|
|
Iron Bug |
24.10.2013, 0:31
Сообщение
#7
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
в твоем коде указатель используется прямо на месте, то есть любой умный указатель в принцепе подойтед. функция go завершит исполнение и объект уничтожится.. никто тебе не запрещает передавать объект в go() извне, а внутри передавать его дальше. я просто привела простой пример. go() там, кстати, только для демонстрации использования this в лямбда-функциях (у тебя он зачем-то прилеплен в вызовах). если в этот пример подставить shared_ptr, то он будет потокобезопасный и у него может быть сколько угодно копий. я просто думала, что у тебя вызовы последовательно используют объект. Внимание! "потокобезопасность" shared_ptr - это лишь безопасность обращений к самому указателю: безопасный счётчик ссылок и вызов деструктора объекта. сам объект, на который он указывает, не защищён. и если в разных потоках происходит изменение этого объекта, то надо ставить мьютексы или ещё какие-то средства синхронизации для обращения к памяти. В случае простой передачи данных (функции thread_func - просто заглушки в том месте, где нужно вызвать создание потока):
Вот реализация с бустовскими потоками (проверено, это работает): Раскрывающийся текст
Сообщение отредактировал Iron Bug - 24.10.2013, 18:10 |
|
|
alexy |
24.10.2013, 12:12
Сообщение
#8
|
Студент Группа: Участник Сообщений: 44 Регистрация: 4.8.2010 Пользователь №: 1931 Спасибо сказали: 0 раз(а) Репутация: 0 |
о, работает как надо спасибо
объект в shared_ptr уничтожается когда завершаются потоки его использующие. да, класс который я использую разумеется сам потокобезопасный.. там мутексы boost::signals2 и. т.д. зы: почему-то не работал без -Wl,--no-as-needed при линковке с потоками из std.. не подключал pthread? Сообщение отредактировал alexy - 24.10.2013, 12:14 |
|
|
Iron Bug |
24.10.2013, 18:23
Сообщение
#9
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
объект в shared_ptr уничтожается когда завершаются потоки его использующие. да, тут я детали забыла. впрочем, я всегда явно выделяю память и освобождаю. привычка к аккуратному использованию кучи. видимо, со старых времён осталась такая привычка. проверяю обязательно, что память не утекает, даже у больших приложений на многодневных прогонах. зы: почему-то не работал без -Wl,--no-as-needed при линковке с потоками из std.. не подключал pthread? под чем собираешь? с какими опциями? иногда у конкретных версий-систем бывают разные особенности. ну и сторонние библиотеки можно по-разному собирать. Сообщение отредактировал Iron Bug - 24.10.2013, 18:49 |
|
|
Iron Bug |
24.10.2013, 20:53
Сообщение
#10
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
а std::bind я так понимаю уничтожает привязанные боъекты тогда, когда уничтожается объект, возращаенной это функцией, так? bind ничего не делает сам. существование объектов должен обеспечить программист. то есть, если ты передал в bind какой-то объект, то он должен существовать во время вызова полученного функтора. shared_ptr при связывании увеличит счётчик и объект не уничтожится, пока вызов не пройдёт. вот пример передачи shared_ptr в bind, с потоками: Раскрывающийся текст
на этот раз не стала писать по старой привычке, через boost , сделала всё через std. хотя я не сравнивала скорость реализаций. это ещё открытый вопрос. Сообщение отредактировал Iron Bug - 24.10.2013, 21:00 |
|
|
Текстовая версия | Сейчас: 2.1.2025, 22:30 |