从 STL std::queue 中删除而不破坏删除的对象?

发布于 2024-08-06 19:13:02 字数 592 浏览 1 评论 0原文

我在 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?

All the documentation I can find on the STL containers (both queue and list) say that for any of the remove functions the removed object's destructor is called. This means that I can't use std::queue any time I want a queue that's simply a list of objects needing some operation performed on them.

I want to be able to add objects to the queue when they are waiting in line for me to do something to them. Then I want to remove them from it when I've finished with them, without destroying the object in question. This doesn't appear to be possible from the documentation I've read. Am I misreading the documentation? Is there another type of queue in the STL other than the basic "queue" that doesn't call the removed object's destructor on a call to pop_front?

Edit to clarify: In my case I'm using a list of pointers. Something like this:

   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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

感情废物 2024-08-13 19:13:02

如果您将指向对象的指针放入队列(以及任何其他 STL 容器)中,则当您删除它们时,这些指针不会被删除。

详细说明:当您使用 std::queue 并删除对象时,会调用 some_obj* 的析构函数。但是普通指针(或任何 POD 类型 - int、char 等)的析构函数是空的,无操作。这里的要点是 some_obj* 的析构函数与 some_obj 的析构函数非常不同。

If you put pointers to objects in the queue (and any other STL container), the pointers won't get deleted when you remove them.

To elaborate: when you use std::queue and remove an object the destructor of some_obj* is called. But the destructor for plain pointer (or any POD type - int, char, etc) is empty, no-op. The fine line here is that the destructor for some_obj* is very different from the destructor for some_obj.

薄荷梦 2024-08-13 19:13:02

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<>。引用包装器是一个代理对象,它包含对原始对象的引用,并且本身是可复制的。与普通原始指针相比的优点是,阅读代码可以清楚地看出资源是在队列外部管理的:从队列中提取数据的代码不需要删除对象。与智能指针方法相比的优点是您无需重新设计系统的其他部分即可使用智能指针。缺点是,与原始指针方法一样,您必须手动确保所引用对象的生命周期比容器中的引用的生命周期长。

STL containers have value semantics. When you push an object into an STL container, the STL container keeps it's own copy of the object, and when the object (internal copy) is removed from the container it is destroyed.

If you used a container of a proxy type, as raw pointers, smart pointers (shared_ptr, weak_ptr), or adapters (as boost::reference_wrapper), then the STL container will destroy the proxy but not the type. Choosing one over the others is usually a matter of how you want to deal with resources.

The most common idiom is using raw pointers, but they don't explicit who is in charge of destruction (the code that pulls from the container should delete the pointer, or the resource is handled somewhere else?).

Modern usage moves towards the shared_ptr approach, as it dilutes the ownership problem. The object will be guaranteed to be alive when you take it out of the container, and if nobody else holds a shared_ptr then the object will automatically be deleted when the local shared_ptr goes out of scope. Using a weak_ptr will keep the ownership in the original code, but will allow you to check for validity of the pointer (if it was deleted) before usage. This could allow you to avoid performing the operation on an object that will be removed right away.

The problem with the shared_ptr/weak_ptr approach is that it forces you to use shared_ptr to hold the original resource. This means that you will not be able to put a pointer into a subobject (member attribute) of another class without redesigning the class to hold the attribute through a shared_ptr, and that will have other implications (the attributes will no longer be contiguous in memory, more dynamic allocation operations will be required...)

A technique that is hardly seen is using adapters as boost::reference_wrapper<>. A reference wrapper is a proxy object that contains a reference to the original object and is itself copyable. The advantage over plain raw pointers is that reading the code it is clear that the resource is managed outside of the queue: the code that pulls data from the queue does not need to delete the object. The advantage over the smart pointer approach is that you do not need to redesign other parts of your system to use smart pointers. The disadvantage is that, as in the raw pointer approach, you must ensure that the lifetime of the referred object outlives the reference in the container manually.

離殇 2024-08-13 19:13:02
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::queueShared_ptr; >

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

If you don't want someobj_t to be copied you could use std::queue< shared_ptr<someobj_t> >.

桜花祭 2024-08-13 19:13:02

使用指向对象的指针列表怎么样?

How about using a list of pointers to the objects?

Bonjour°[大白 2024-08-13 19:13:02

认为容器中的项目位于该容器的“范围内”,当从容器中删除项目时,就像离开函数的范围一样。如果变量是指针,则在离开作用域时该项目不会发生任何变化。如果变量是本地堆栈,则在离开作用域时将自动调用析构函数。

在容器中存储指针与分配到本地原始指针具有相同的缺点,内存不会自动清理。在函数中,如果您不删除指针或通过返回指针来转移所有权,那么就会出现内存泄漏。

当将原始指针存储在容器中时,所有权可能会变得有点模糊,并且很容易发生泄漏。查看 tr1::shared_ptr 并将其存储在容器中。

C++0x 中的 std::unique_ptr 也是在 stdlib 容器可用时将指针存储在其中的一个很好的解决方案。

Think of item's in a container being "in-scope" of that container, when an item is removed from a container it is just like leaving the scope of a function. If the variable is a pointer nothing happens to the item when leaving the scope. If variable is a stack local then destructor will will be automatically called upon leaving the scope.

Storing pointers in containers have the same downfalls as allocating into a local raw pointer, the memory is not cleaned up automatically. In a function if you don't delete the pointer or transfer ownership by returning it then you have a memory leak.

When storing raw pointers in a container the ownership can become a bit ambiguous and leaks can easily happen. Take a look at tr1::shared_ptr and store those in the containers instead.

std::unique_ptr in C++0x would also be a good solution for storing a pointer in a stdlib container when it is available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文