使用STL队列pop()销毁类指针



当您通过some_queue.front()获取指针,将其分配给另一个变量,然后调用some_queue.pop()时会发生什么?谁应该清理内存?(我使用的是c++98,如果真的需要,我可以使用boost智能指针)

例如:(为什么这样做?或者不应该这样做?)

class SClass {
public:
    SClass(int si): sInt(si){}
    int getSInt(){ return sInt; }
private:
    int sInt;
    ... // bunch of other complicated data types so copy might be slow
};
int main()
{
   cout << "Hello World" << endl; 
   queue<SClass *> sq;
   for(int i = 0; i < 10; i++){
       SClass *sc = new SClass(i);
       sq.push(sc);
   }
   SClass *s2 = NULL;
   while(!sq.empty()){
       s2 = sq.front();
       sq.pop();
       cout << s2->getSInt() << endl;
   }
   delete s2;
   return 0;
}

此处的工作测试代码:http://cpp.sh/6z7ke

在您的例子中,queue只管理指针本身,它对所指向的内存不做任何事情。在您的示例中,您泄漏了前九个SClass,只删除了最后一个。

如果你不明确地需要,你就不应该动态分配你的对象。试试这个:

int main()
{
   cout << "Hello World" << endl; 
   queue<SClass> sq;
   for(int i = 0; i < 10; i++){
       sq.push(i);
   }
   while(!sq.empty()){
       SClass& s2 = sq.front();
       cout << s2.getSInt() << endl;
       sq.pop();
   }
   return 0;
}

在这种情况下,对象在push进入队列时创建,在pop进入队列时销毁。如果我们忽略可能的性能问题(创建一个临时SClass作为queue.push()的参数,并将其复制到队列内部缓冲区;这是可以优化的,但这是另一个主题),这是一种更干净、可读的方法。


如果您的对象很大,并且您希望确保它们不会被无用地复制,那么您应该使用std::queue<std::unique_ptr<SClass>>或为SClass提供移动构造函数。这有点超出了范围,所以如果需要的话,我会让你再问一个问题。

当您通过some_queue.front()获取指针,将其分配给另一个变量,然后调用some_queue.pop()时,会发生什么?

对象的副本存储在另一个变量中,并从队列顶部删除。

谁应该清理内存?

谁分配了内存。

为什么这样做?

乍一看,它似乎没有任何理由不起作用。但是,您确实泄漏了大部分已分配的SClass对象(除底部对象外的所有对象)。要修复泄漏,请删除从队列中获得的指针,然后再将其重新分配给另一个值(在循环结束时)。更好的是,不要手动分配内存,而是使用对象队列而不是指针队列。

如果包含的元素类型为指针,则std::queue::pop()不会释放内存。在所有标准容器的情况下,用户必须确保释放原始指针所拥有的内存。
while(!sq.empty()){
       s2 = sq.front();
       sq.pop();
       cout << s2->getSInt() << endl;
       // memory should be freed here
       delete s2;
   }

最新更新