2

我有一个队列类,其中我试图动态分配 3 个“样本”对象并将它们放入队列中,然后出列并删除它们。但是示例对象的析构函数:

~Sample() { cout << "Destructing Sample object " << id << "\n"; }

当我尝试将对象放入队列时,由于某种原因被调用。

int main()
{
   Sample *samp1;
   Sample *samp2;
   Sample *samp3;
   Queue<Sample> sQa(3);
   samp1 = new Sample(1);
   samp2 = new Sample(2);
   samp3 = new Sample(3);

   cout << "Adding 3 Sample objects to queue...\n";

   sQa.put(*samp1);
   sQa.put(*samp2);
   sQa.put(*samp3);

   cout << "Dequeing and destroying the objects...\n";

   for(int i = 0; i < 3; ++i)
   {
       delete &sQa.get();
   }

   return 0;
}

这是输出:

Adding 3 sample objects to queue...
Destructing Sample object 1
Destructing Sample object 2
Destructing Sample object 3
Dequeing and destroying the objects...
Destructing Sample object 1

然后程序崩溃。有谁知道这可能是为什么?此外,如果有必要,这里是 put 函数。(队列类是一个模板)

void put(Qtype data) 
{
    if(putloc == size) 
    {
        cout << " -- Queue is full.\n";
        return;
    }

    putloc++;
    q[putloc] = data;   
}
4

4 回答 4

10

您的代码会导致未定义的行为。它调用delete未使用动态分配的对象new

和:

sQa.put(*samp1);

您将动态分配的成员的副本存储在sQa. 一旦按值复制对象,就会丢失指向动态分配对象的指针。

解决方案是使用智能指针作为容器元素,让 RAII 为您完成所有繁重的内存管理工作。

于 2013-05-23T14:56:32.140 回答
3

你问题的根源

delete &sQa.get();

您正在删除与分配的对象无关的内容new

正确的方法如下:

Queue<Sample*> sQa(3);
samp1 = new Sample(1);
samp2 = new Sample(2);
samp3 = new Sample(3);

sQa.put(samp1);
sQa.put(samp2);
sQa.put(samp3);

cout << "Dequeing and destroying the objects...\n";

for(int i = 0; i < 3; ++i)
{
   delete sQa.get();
}

注意:最好使用智能指针,例如unique_ptrshared_ptr代替裸指针。

于 2013-05-23T14:56:40.100 回答
1

除非 Qtype 是 typedef,否则您的 put() 函数指定其参数应通过副本传递。无论何时调用它,它都会调用 Sample 的复制构造函数来创建一个临时对象。

于 2013-05-23T14:58:59.993 回答
1

您的代码分配对象;将它们复制到队列中;从队列中检索副本;并尝试删除这些副本。原始对象被泄露(因为你没有delete samp1等),并且最终对象不能被删除,因为它们不是用new.

您看到的析构函数来自将分配的对象复制到队列中时创建的临时对象;崩溃是您从删除错误对象中得到的未定义行为。

由于队列包含对象,而不是指针,因此根本没有必要搞乱动态分配:

cout << "Adding 3 Sample objects to queue...\n";

sQa.put(Sample(1));
sQa.put(Sample(2));
sQa.put(Sample(3));

cout << "Dequeing and destroying the objects...\n";

for(int i = 0; i < 3; ++i)
{
   sQa.get();
}

如果你想尝试动态分配,那么你应该修改队列来存储指针;但请记住,如果没有RAII的帮助,管理动态对象是非常困难的,所以不要在任何需要可靠的代码中尝试这样做。

于 2013-05-23T15:06:53.603 回答