2010-11-14 4 views
0

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

//-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) 

Является ли это лучшим решением для такой ситуации?

ответ

6

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

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

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

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

Автоматическое управление ресурсами в C++ выполняется с использованием шаблона проектирования Resource Acquisition is Initialization (RAII), который, возможно, является самым важным шаблоном проектирования, которым вы, как программист на C++, должны ознакомиться.

+0

+1: Самая важная причина, по которой это хорошее решение, заключается в том, что с помощью умного указателя они больше не могут напрямую вызывать удаление объекта, не имея явно явно неправильных/явно злых хаков. Есть и другие преимущества, как уже писал Джеймс, но это тот самый, который наиболее применим к вопросу. –

0

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

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

1

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

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

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

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

+0

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

2

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

2

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

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

Смежные вопросы