Надежное обеспечение безопасности памяти в C++ 14

Я преобразовываю старый код C++ для использования shared_ptr, unique_ptr и weak_ptr и продолжаю сталкиваться с проблемами проектирования.

У меня есть методы «генератора», которые возвращают новые объекты, и методы доступа, которые возвращают указатели на существующие объекты. На первый взгляд решение кажется простым; вернуть shared_ptr для новых объектов и weak_ptr для средств доступа.

shared_ptr полностью избегает висячих указателей, поскольку, если объект когда-либо будет удален, все его общие и слабые указатели узнают об этом. Но я продолжаю сталкиваться со случаями, когда я не уверен, есть ли циклические ссылки среди моих общих указателей. Классов много, и некоторые из них указывают друг на друга; возможно ли, что в какой-то момент сформировался цикл? Код настолько сложен, что трудно сказать - новые классы создаются по инструкциям в файле скрипта. Так что я не знаю, действительно ли shared_ptr предотвращает утечку памяти и вручную удаляет все объекты, что, кажется, противоречит сути.

Вместо этого я решил использовать unique_ptr, так как мне фактически не нужно где-либо совместное владение. (В старом коде C++, конечно, не было общего владения, это были только необработанные указатели.) Но я не могу сделать weak_ptrs из unique_ptr, поэтому мне приходится использовать необработанные указатели в качестве заменителей для слабых указателей. Это решает проблему утечки памяти, но я могу остаться с оборванными указателями, когда unique_ptr будет уничтожен.

Таким образом, кажется, что я могу иметь одно или другое: пуленепробиваемое предотвращение утечки памяти или пуленепробиваемое предотвращение оборванного указателя, но не оба.

Люди говорили мне, что мне нужно держать всю структуру программы в голове, чтобы я мог убедиться, что нет циклов с общими указателями, но это кажется подверженным ошибкам. Моя голова, в конце концов, только такая большая. Есть ли способ обеспечить безопасность памяти, учитывая только локальный код?

Для меня это центральный принцип объектно-ориентированного программирования, и, кажется, в данном случае я его упустил.


person Ebonair    schedule 19.01.2018    source источник
comment
См. это: stackoverflow.com/questions/18525845/   -  person Anton Savin    schedule 20.01.2018
comment
Безопасность памяти не обеспечивается, если на все налепить special_pointer_t. Безопасность памяти обеспечивается за счет избегания указателей, когда это возможно, и использования вместо них значений, а также четкого понимания того, кто чем владеет.   -  person nwp    schedule 20.01.2018
comment
@AntonSavin Я думал о чем-то подобном, но больше думал о создании пользовательского unique_ptr со слабыми ссылками, а не о shared_ptr без совместного использования. Я полагаю, что они оба примерно эквивалентны.   -  person Ebonair    schedule 20.01.2018
comment
Управление ресурсами — это проблема любого программирования, а не только объектно-ориентированного программирования. Старый код работает корректно? Если да, то, вероятно, лучше оставить его в покое. Если нет, сядьте и наметьте обязанности каждого и перепишите код в соответствии с этим. То, что у вас есть, было написано с учетом конкретной идиомы управления памятью, и оно может не подходить для того, что вы имеете в виду. Например, если у него есть проблема с оборванными указателями, я бы порекомендовал сначала разобраться, почему ссылки болтаются, а не накладывать пластырь.   -  person user4581301    schedule 20.01.2018
comment
следствием unique_ptr являетсяObserver_ptr или reference_wrapper   -  person Richard Hodges    schedule 20.01.2018
comment
Один из быстрых способов узнать, есть ли у вас проблемы с циклическими ссылками: запустить вашу программу под управлением valgrind (и убедиться, что ваша программа выходит контролируемым образом, например, путем возврата из main()). Если при завершении вашей программы valgrind сообщает об утечке памяти, выясните причину и, если возможно, исправьте. Повторяйте до тех пор, пока valgrind не сообщит об утечках памяти - в этот момент вы находитесь в довольно хорошем состоянии.   -  person Jeremy Friesner    schedule 21.01.2018


Ответы (1)


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

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

Поскольку «создано до» — это полный порядок, это гарантирует, что граф общих указателей является ациклическим.

person Matt Timmermans    schedule 20.01.2018
comment
Спасибо! Это хороший процедурный способ решения проблемы. - person Ebonair; 22.01.2018