Удаление из STL std:: queue без уничтожения удаленного объекта?
вся документация, которую я могу найти в контейнерах STL (как очередь, так и список), говорит, что для любой из функций remove вызывается деструктор удаленного объекта. Это означает, что я не могу использовать std::queue в любое время, когда я хочу очередь, которая просто список объектов, нуждающихся в некоторой операции, выполняемой над ними.
Я хочу иметь возможность добавлять объекты в очередь, когда они ждут в очереди, чтобы я что-то с ними сделал. Затем я хочу удалить их из него, когда я закончу с их, не разрушая объект, о котором идет речь. Из документации, которую я читал, это кажется невозможным. Я неправильно читаю документацию? Есть ли другой тип очереди в STL, отличный от базовой "очереди", которая не вызывает деструктор удаленного объекта при вызове pop_front?
редактировать для уточнения: в моем случае я использую список указателей. Что-то вроде этого:--2-->
dbObject *someObject;
queue<dbObject *> inputQueue;
inputQueue.push_back(someObject);
...
dbObject *objectWithInput = inputQueue.front();
//handle object's input...
inputQueue.pop_front(); // Remove from queue... destroyed now?
5 ответов
Если вы поместите указатели на объекты в очереди (и любой другой контейнер STL), указатели не будут удалены при их удалении.
для разработки: при использовании std:: queue и удалении объекта вызывается деструктор some_obj*. Но деструктор для простого указателя (или любого типа POD-int, char и т. д.) пуст, no-op. Тонкая линия здесь заключается в том, что деструктор для some_obj* сильно отличается от деструктора для some_obj.
контейнеры STL имеют семантику значений. Когда вы помещаете объект в контейнер STL, контейнер STL сохраняет собственную копию объекта, а когда объект (внутренняя копия) удаляется из контейнера, он уничтожается.
Если вы использовали контейнер типа прокси, как необработанные указатели, интеллектуальные указатели (shared_ptr, weak_ptr) или адаптеры (как boost::reference_wrapper), то контейнер STL уничтожит прокси, но не тип. Выбор одного из них над другими обычно вопрос о том, как вы хотите иметь дело с ресурсами.
наиболее распространенной идиомой является использование необработанных указателей, но они не указывают, кто отвечает за уничтожение (код, который извлекает из контейнера, должен удалить указатель, или ресурс обрабатывается где-то еще?).
современное использование движется к подходу shared_ptr, поскольку он разбавляет проблему владения. Объект будет гарантированно жив, когда вы вытащите его из контейнера, и если никто другой не держит shared_ptr, то объект будет автоматически удален, когда локальный shared_ptr выходит за рамки. Использование weak_ptr сохранит право собственности в исходном коде, но позволит вам проверить правильность указателя (если он был удален) перед использованием. Это может позволить вам избежать выполнения операции над объектом, который будет удален сразу.
проблема с подходом shared_ptr/weak_ptr заключается в том, что он заставляет вас использовать shared_ptr для хранения исходного ресурса. Этот означает, что вы не сможете поместить указатель в подобъект (атрибут-член) другого класса без перепроектирования класса для хранения атрибута через shared_ptr, и это будет иметь другие последствия (атрибуты больше не будут смежными в памяти, потребуются более динамические операции выделения...)
метод, который вряд ли можно увидеть, использует адаптеры в качестве boost:: reference_wrapper. Оболочка ссылок-это прокси-объект, содержащий ссылку на исходный объект и сам является копируемым. Преимущество перед простыми необработанными указателями заключается в том, что при чтении кода ясно, что ресурс управляется вне очереди: код, который извлекает данные из очереди, не должен удалять объект. Преимущество метода интеллектуальных указателей заключается в том, что для использования интеллектуальных указателей не требуется перепроектировать другие части системы. Недостатком является то, что, как и в подходе raw pointer, необходимо убедиться, что время существования указанного объекта истекает ссылка в контейнере вручную.
class someobj_t {};
std::queue<someobj_t> q;
...
someobj_t ppd = q.front(); // ppd is not a reference
q.pop();
// ppd now contain removed object
Если вы не хотите someobj_t
для копирования вы можете использовать std::queue< shared_ptr<someobj_t> >
.
подумайте о том, что элемент в контейнере находится "в области" этого контейнера, когда элемент удаляется из контейнера, это похоже на выход из области функции. Если переменная является указателем, то при выходе из области с элементом ничего не происходит. Если переменная является локальной стеком, деструктор будет автоматически вызываться при выходе из области.
хранение указателей в контейнерах имеет те же недостатки, что и выделение в локальный необработанный указатель, память не очищается автоматически. В функции, если вы не удаляете указатель или не передаете право собственности, возвращая его, у вас есть утечка памяти.
при хранении необработанных указателей в контейнере владение может стать немного неоднозначным, и утечки могут легко произойти. Взгляните на tr1:: shared_ptr и сохраните их в контейнерах.
std:: unique_ptr в C++0x также будет хорошим решением для хранения указателя в контейнере stdlib, когда он доступен.