我可以在STL容器(队列和列表)上找到的所有文档都说,对于任何删除函数,都会调用已删除对象的析构函数。这意味着每当我想要一个只需要对它们执行某些操作的对象列表的队列时,我就不能使用std :: queue。
我希望能够在排队让我对他们做某些事情时将对象添加到队列中。然后我想在完成它们之后将它们从它上移除,而不会破坏有问题的物体。从我读过的文档中看似不可能。我误读了文档吗?除了在调用pop_front时没有调用被删除对象的析构函数的基本“队列”之外,STL中是否存在另一种类型的队列?
编辑澄清:在我的情况下,我正在使用指针列表。像这样:
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?
答案 0 :(得分:17)
如果将指针放在队列中的对象(以及任何其他STL容器)中,则删除指针时不会删除指针。
详细说明:当你使用std :: queue并删除一个对象时,会调用some_obj *的析构函数。但是普通指针(或任何POD类型 - int,char等)的析构函数是空的,无操作。这里的细线是some_obj *的析构函数与some_obj的析构函数非常不同。
答案 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&lt;&gt;。引用包装器是一个代理对象,它包含对原始对象的引用,并且本身是可复制的。与普通原始指针相比,优势在于读取代码很明显资源是在队列外部管理的:从队列中提取数据的代码不需要删除对象。智能指针方法的优势在于您无需重新设计系统的其他部分即可使用智能指针。缺点是,与原始指针方法一样,您必须确保引用对象的生命周期超过容器中的引用。
答案 2 :(得分: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> >
。
答案 3 :(得分:3)
如何使用指向对象的指针列表?
答案 4 :(得分:2)
将容器中的项目视为该容器的“范围内”,当从容器中移除项目时,它就像离开函数的范围一样。如果变量是指针,则在离开范围时项目没有任何反应。如果变量是本地堆栈,那么析构函数将在离开范围时自动调用。
在容器中存储指针与分配到本地原始指针具有相同的缺点,内存不会自动清理。在函数中,如果您不通过返回指针删除指针或转移所有权,那么您就会发生内存泄漏。
在容器中存储原始指针时,所有权可能会变得有点模糊,并且很容易发生泄漏。看看tr1 :: shared_ptr并将它们存储在容器中。
C ++ 0x中的std :: unique_ptr也是一个很好的解决方案,用于在stdlib容器可用时将指针存储。