shared_ptr

May. 2nd, 2014 10:28 pm
sab123: (face)
[personal profile] sab123
Попытался использовать shared_ptr из C++11. Ну что я могу сказать, люди, создавшие напрочь бесполезный auto_ptr, сумели создать почти столь же бесполезный счетчик ссылок. Фундаментальная проблема в том, что они пытаются делать счетчик ссылок для совершенно любых структур, и потому хранят сам счетчик не прямо в структуре, а отдельно. При присвоении указателя в shared_ptr в первый раз оно создает отдельную структуру со счетчиком. И если потом присваивать эти shared_ptr друг к другу, то оно работает нормально. Но если взять и опять положить изначальный указатель в другой shared_ptr, то образуется два отдельных счетчика для одной структуры, и все погибает. И совершить такую ошибку очень легко. В-общем, этой штукой пользоваться нельзя. Мой темплейт Autoptr - гораздо, гораздо лучше.

P.S. Проблема разъяснилась. Надо просто никогда не конструировать такие объекты напрямую, а использовать make_shared. Ну, или статические методы, возвращающие прямо ссылку. И тогда указатели не вылазят наружу.

Date: 2014-05-03 05:35 am (UTC)
From: [identity profile] rezkiy.livejournal.com
>> взять и опять положить изначальный указатель

А это разве не поперек идеологии RAII? Получил поинтер / хендл, засунь в смартпоинтер и убери руки. Брать и положить нельзя.

Date: 2014-05-03 05:44 am (UTC)
From: [identity profile] sab123.livejournal.com
Если это такая идеология, то это плохая, негодная идеология. Слишком легко ломается. То есть, по сути - да, чтобы указатель куда-то ложить, то он должен быть уже заведомо в какой-то активной ссылке. Но за этим следить гораздо проще, чем за тем, чтобы не ложить указатели в ссылки по второму разу.

Date: 2014-05-03 05:56 am (UTC)
From: [identity profile] rezkiy.livejournal.com
ну у нас анменеджед среда же, все легко ломается при отсутствии должной дисциплины.

А где посмотреть как именно вы считаете рефкаунты?

Date: 2014-05-03 06:10 am (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Но если взять и опять положить изначальный указатель в другой твой Autoptr, то что будет?

Date: 2014-05-03 06:17 am (UTC)
From: [identity profile] sab123.livejournal.com
+1 к тому же счетчику.

Date: 2014-05-03 06:24 am (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Который где? Внутри объекта? А weak_ptr как делать?
Edited Date: 2014-05-03 06:30 am (UTC)

Date: 2014-05-03 06:27 am (UTC)
From: [identity profile] sab123.livejournal.com
Но хотелось бы, чтобы сломать было сложнее, а не "первый же залетевший дятел разрушил цивилизацию".

Вкратце описано оно здесь:

http://babkin-cep.blogspot.com/2012/08/reference-counting.html
http://babkin-cep.blogspot.com/2012/08/autoref-summary.html

И код тут:

http://sourceforge.net/p/triceps/code/HEAD/tree/trunk/cpp/mem/

Date: 2014-05-03 06:30 am (UTC)
From: [identity profile] sab123.livejournal.com
Прямо в учитываемой структуре. Что гораздо лучше и надежнее, чем плодить счетчики отдельно.

Date: 2014-05-03 06:33 am (UTC)
From: [identity profile] rezkiy.livejournal.com
спасибо, почитаю.

Date: 2014-05-03 06:34 am (UTC)
From: [identity profile] rezkiy.livejournal.com
>> Прямо в учитываемой структуре

Я еще не читал, но это пахнет комом. Не то чтобы с комом что-то было не так, но все украдено до нас, и есть проблема с кольцевыми ссылками.

Date: 2014-05-03 06:42 am (UTC)
From: [personal profile] alll
Оно и так прекрасно ломается. Возьмёт кто-то достаточно упоротый raw указатель одновременно со smart и будет хранить его отдельно. Такие вещи в C++ пресекаются только на уровне coding policy/peer review/анализаторов кода.

Date: 2014-05-03 06:46 am (UTC)
From: [personal profile] alll
Так вроде у всех смарт-пойнтеров проблема с кольцевыми ссылками. Для её разруливания нужны weak-пойнтеры, которые вроде как тоже есть.

Date: 2014-05-03 07:17 am (UTC)
From: [identity profile] rezkiy.livejournal.com
в коме нету.

Date: 2014-05-03 07:23 am (UTC)
From: [identity profile] sab123.livejournal.com
А в чем проблема с weak_ptr? Ну, сделать его отдельным объектом. На который хранить ссылку в изначальном объекте. Он на самом деле вообще не очень-то и нужен.

Но вообще похоже, что я догадался, как надо делать с shared_ptr чтобы он не ломался: во всех классах, предназначенных для использования с ним, делать конструкторы защищенными, а вместо них использовать статические функции, которые будут возвращать сразу shared_ptr (возможно, делая make_shared, но непонятно, не делает ли он копирования объекта). И тогда простые указатели совсем исчезают, и сломать логику делается сложно.

Date: 2014-05-03 07:26 am (UTC)
From: [identity profile] sab123.livejournal.com
Вместо слабых ссылок можно использовать обычные указатели (предполагается, что указыываемй объект является родителем данного объекта в иерархии, и потому раньше него исчезнуть не может).

Date: 2014-05-03 07:35 am (UTC)
From: [identity profile] sab123.livejournal.com
Я про ком не читал, но свою версию я тоже не с пустого места придумал :-) Впрочем, как я уже написал ниже, главная проблема - то, что чтобы положить только что сконструированный объект в уже существующую ссылку, надо делать reset(ptr). Что способствует ошибочному деланию reset(ptr) и из прочих указателей. Если сделать указатели невидимыми, то reset(ptr) просто делается никогда не нужен и проблема уходит. Сделать их невидимыми можно или обернув конструкторы в статические функции, возвращающие ссылки, или всегда делать такое конструирование в два шага:

shared_ptr<Object> p = new Object;
somewhere->field_shared_ptr = p;

Ну, или в одну строчку

somewhere->field_shared_ptr = shared_ptr<Object>(new Object);
somewhere->field_shared_ptr = make_shared<Object>(new Object);
Edited Date: 2014-05-03 07:36 am (UTC)

Date: 2014-05-03 07:40 am (UTC)
From: [identity profile] sab123.livejournal.com
О, оказалось, что make_shared - это и есть такой готовый оборачивающий статический метод, который пропускает аргументы насквозь к конструктору.

Date: 2014-05-03 11:04 am (UTC)
From: [personal profile] alll
Можно, но возможно не стоит. Слишком сильное ограничение, не всегда возможно соблюсти, ещё менее всегда можно навязать всей команде, сложно отловить анализаторами кода или в code review.

Date: 2014-05-03 04:02 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
make_shared же и все дела
ой, ну да, дочитал :)
кстати. проблемы с оборачиванием одной и той же структуры в два шейрда ни разу не наблюдал

Date: 2014-05-03 04:05 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
там только кэтч есть какой-то, копироваться они что ли должны, аргументы эти
но я про бустовую версию

Date: 2014-05-03 04:32 pm (UTC)
From: [identity profile] sab123.livejournal.com
В раельности оно почти всегда соблюдается. А когда не соблюдается, то дело сводится к делению объектов. То есть, например, есть у нас объекты A и B, которым надо ссылаться друг на друга. Более близкое изучение показывает, что на самом деле объекту B нужен не весь объект A, а только небольшая часть его. Выделяем эту часть в объект C. И в результате A ссылается на B и C, а B ссылается на C.

Date: 2014-05-03 04:35 pm (UTC)
From: [identity profile] sab123.livejournal.com
Я за полчаса сумел :-) Но у меня, конечно, имеются рефлексы от другой методы счетчика.

Date: 2014-05-03 04:37 pm (UTC)
From: [identity profile] sab123.livejournal.com
Ну да, чтоб оно работало хорошо, надо C++11 - там темплейты могут пропускать насквозь аргументы, как через макро.

Вообще, конечно, с точки зрения эффективности оно все равно проигрывает, с лишними копированиями ссылок и изменениями счетчика, но это уже фигня, жить можно.

Date: 2014-05-03 08:10 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
ну, деференсирование там бесплатное
а передавать можно и реф на шейрд, там где копировать не нужно
я бустовые шейрды использую уже лет 10 наверное, даже если есть оверхед в 1-2%, это покрывается кастомными аллокаторами ну и просто тем что руками с памятью работать не нужно
кстати в майкрософте народ как-то умудрился оптимизировать shared_ptr, надо почитать, gcc'шная версия по крайней мере на 4.7 проигрывала

еще есть нюанс при сильно многопоточной обработке, если вдруг в дизайне (по ошибке) есть набор каких-то шейрдов, которые зачем-то часто копируются/удаляются и они рядом в памяти, то могут быть проблемы с когерентностью кэш-линий (в том плане что копирование адски замедляется), надо их как-нибудь раскидать в памяти или передизайнить

Date: 2014-05-03 08:13 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
там еще прикольная штука есть, shared_from_this
полезно при всякой там асинхронной обработке через boost::asio например

Date: 2014-05-03 11:12 pm (UTC)
From: [identity profile] sab123.livejournal.com
Я в смысле, в сравнении с альтернативным вариантом, когда счетчик - прямо в объекте.

January 2026

S M T W T F S
     12 3
45 6 7 8 9 10
11 12 13 14 151617
1819202122 23 24
25 262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 27th, 2026 02:58 am
Powered by Dreamwidth Studios