2009-10-03 2 views
7

Вся документация, которую я могу найти в контейнерах STL (как в очереди, так и в списке), говорит, что для любой из функций удаления вызывается деструктор удаленного объекта. Это означает, что я не могу использовать std :: queue в любое время, когда я хочу, чтобы очередь была просто списком объектов, нуждающихся в некоторой операции, выполняемой над ними.Удаление из STL std :: queue без разрушения удаленного объекта?

Я хочу иметь возможность добавлять объекты в очередь, когда они ждут очереди, чтобы я мог что-то сделать с ними. Затем я хочу удалить их из него, когда я закончил с ними, не уничтожая объект, о котором идет речь. Это не представляется возможным из документации, которую я прочитал. Я неправильно понимаю документацию? Есть ли другой тип очереди в STL, кроме базовой «очереди», которая не вызывает деструктор удаленного объекта при вызове pop_front?

Изменить, чтобы уточнить: В моем случае я использую список указателей. Что-то вроде этого:

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? 
+1

Если вы храните указатели внутри очереди, их удаление не будет вызывать деструктор. –

+0

Аналогичный вопрос: http://stackoverflow.com/questions/1525535/delete-all-items-from-a-c-stdvector –

ответ

17

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

Чтобы разработать: когда вы используете std :: queue и удаляете объект, вызывается деструктор some_obj *. Но деструктор для простого указателя (или любого типа POD - int, char и т. Д.) Пуст, no-op. Тонкая линия здесь заключается в том, что деструктор для some_obj * сильно отличается от деструктора для some_obj.

+2

Точно. И только для справки, если вы на самом деле когда-либо хотите контейнер для удаления объектов с указаными объектами, вам нужно либо сохранить какой-то умный указатель, либо использовать что-то вроде указателей-указателей boost. – TheUndeadFish

3

Как насчет использования списка указателей на объекты?

+0

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

4
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> >.

+0

Я использую список указателей. –

+1

Тогда реальный объект не будет уничтожен при стирании. –

7

Контейнеры 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 <>. Опорная оболочка - это прокси-объект, который содержит ссылку на исходный объект и сам можно копировать. Преимущество над обычными указателями состоит в том, что при чтении кода ясно, что ресурс управляется за пределами очереди: код, который извлекает данные из очереди, не нуждается в удалении объекта. Преимущество подхода smart pointer заключается в том, что вам не нужно перепроектировать другие части вашей системы, чтобы использовать интеллектуальные указатели. Недостаток заключается в том, что, как и в подходе с необработанным указателем, вы должны убедиться, что время жизни упомянутого объекта обходит ссылку в контейнере вручную.

+0

Мне нравится, как вы объяснили и сформулировали этот ответ, очень полезный и очень полный. – joshperry

2

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

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

При хранении необработанных указателей в контейнере право собственности может стать немного неоднозначным, и утечки могут легко произойти. Посмотрите на tr1 :: shared_ptr и сохраните их в контейнерах.

std :: unique_ptr в C++ 0x также будет хорошим решением для хранения указателя в контейнере stdlib, когда он будет доступен.

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