Как предотвратить удаление указателя без использования const? - PullRequest
0 голосов
/ 15 ноября 2010

У меня есть класс, который содержит вектор указателей объектов.У меня есть функция GetObject (..) в этом классе, которая просматривает вектор, находит нужный объект и возвращает указатель на него.Однако, если пользователь класса выполняет delete () для этого возвращенного указателя, моя программа завершится сбоем, потому что вектор все еще имеет указатель на этот, теперь недопустимый, объект.Итак, в моем классе GetObject () я могу вернуть указатель const, но это не решает проблему, потому что вы все равно можете удалить объект.Объект изменчив, поэтому я не могу вернуть указатель на объект const.Я полагаю, что мог бы предотвратить удаление, возвращая ссылку на объект, но у меня есть функция, возвращающая NULL, если есть ошибка.Я думаю, что могу передать ссылку на объект через параметры, а затем вернуть и номер ошибки, как это

//-1 on object on found. 0 for success. Object is passed back in 
// the function parameter result.
int MyObject::GetObject(int object_id, Item& result)

Это лучшее решение для такой ситуации?

Ответы [ 5 ]

6 голосов
/ 15 ноября 2010

Лучший способ решить эту проблему - использовать интеллектуальный указатель совместного владения, например shared_ptr, который можно найти в Boost, C ++ TR1 и C ++ 0x.

Умный указатель - это контейнер, который управляет временем жизни вашего динамически размещенного объекта. Он берет на себя ответственность за delete объект, когда вы его используете.

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

Крайне сложно управлять ресурсами в C ++ вручную, и очень легко написать код, который выглядит правильно и работает в большинстве случаев, но все же не правильно. Используя интеллектуальные указатели и другие контейнеры-владельцы ресурсов (например, контейнеры стандартной библиотеки), вам больше не нужно управлять ресурсами вручную. Правильно написать правильный код значительно проще, когда все управление вашими ресурсами происходит автоматически.

Автоматическое управление ресурсами в C ++ осуществляется с помощью шаблона проектирования под названием Получение ресурсов - инициализация (RAII) , который, возможно, является наиболее важным шаблоном проектирования, с которым вы, как программист C ++, должны быть знакомы.

2 голосов
/ 15 ноября 2010

Кто клиенты вашего класса?Если они не ваши смертельные враги, вы можете просто попросить их не удалять объект.В противном случае у «них» всегда будет возможность испортить вас.

Хорошо, одно из возможных решений - сделать деструктор приватным.Это помешает всем удалить объект.Но тогда объект должен каким-то образом удалить себя (delete this), возможно, с помощью какой-либо функции, называемой DeletObjectButDontBlameMeIfAppCrashes.Если владельцем является какой-то другой класс, то вы можете установить деструктор в защищенный и владелец класса в качестве друга этого класса.

2 голосов
/ 15 ноября 2010

Любой в вашем коде может также попытаться отменить ссылку на NULL.Ты тоже собираешься их остановить?Если ваш контейнер владеет объектом, и вы четко это объясняете (возвращение необработанного указателя обычно довольно ясно или упоминается в документах), то любой, кто его удалит, будет виноват по своей вине.Единственный способ гарантировать предотвращение удаления объекта - не дать пользователю когда-либо получить собственную ссылку или указатель - в этом случае он просто не сможет получить доступ к объекту.

1 голос
/ 15 ноября 2010

Вы должны вернуть ссылку на объект.Существует два способа обработки случая, когда объект не найден.

Во-первых, вы можете использовать Null Object Pattern для реализации специального значения для этого случая.Это может не иметь смысла для вашего случая.

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

Многие STL-контейнеры или алгоритмы реализуют оба из них, либо возвращая последний итератор, либо имея empty() returns false в качестве предварительного условия для вызова метода, такого как front или back.

0 голосов
/ 15 ноября 2010

Если вы можете использовать библиотеки повышения, можно использовать интеллектуальные указатели , чтобы указатели оставались действительными.По сути, каждая ссылка на интеллектуальный указатель увеличивает свой «счетчик использования» на 1. Когда функция reset вызывается для ссылки, ссылка исчезает, и счетчик использования уменьшается.Пока какой-то объект все еще держится за умный указатель, ссылка будет действительной.Обратите внимание, что другие классы смогут изменять то, на что он указывает, но не могут его удалить.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...