队列:: push之后加倍释放或损坏 [英] Double free or corruption after queue::push

查看:127
本文介绍了队列:: push之后加倍释放或损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#include <queue>
using namespace std;

class Test{
    int *myArray;

        public:
    Test(){
        myArray = new int[10];
    }

    ~Test(){
        delete[] myArray;
    }

};


int main(){
    queue<Test> q
    Test t;
    q.push(t);
}

运行此命令后,出现运行时错误双重释放或损坏 。如果我摆脱了析构函数的内容(删除),它就可以正常工作。

After I run this, I get a runtime error "double free or corruption". If I get rid of the destructor content (the delete) it works fine. What's wrong?

推荐答案

让我们谈谈用C ++复制对象。



Test t; ,调用默认构造函数,该构造函数分配新的整数数组。

Let's talk about copying objects in C++.

Test t;, calls the default constructor, which allocates a new array of integers. This is fine, and your expected behavior.

当您使用<$ c将 t 推入队列时,麻烦就来了$ c> q.push(t)。如果您熟悉Java,C#或几乎所有其他面向对象的语言,则可能希望将您创建的对象添加到队列中,但是C ++不能那样工作。

Trouble comes when you push t into your queue using q.push(t). If you're familiar with Java, C#, or almost any other object-oriented language, you might expect the object you created earler to be added to the queue, but C++ doesn't work that way.

当我们查看 std :: queue :: push 方法,我们看到添加到队列中的元素被初始化为x的副本。它实际上是一个全新的对象,它使用复制构造函数复制原始 Test 对象的每个成员以进行新的 Test

When we take a look at std::queue::push method, we see that the element that gets added to the queue is "initialized to a copy of x." It's actually a brand new object that uses the copy constructor to duplicate every member of your original Test object to make a new Test.

默认情况下,您的C ++编译器会为您生成一个副本构造函数!这很方便,但是会导致指针成员出现问题。在您的示例中,请记住 int * myArray 只是一个内存地址。当 myArray 的值从旧对象复制到新对象时,您现在将有两个对象指向内存中的同一数组。这从本质上来说并不是很糟糕,但是析构函数将尝试两次删除同一数组,因此会出现双重释放或损坏运行时错误。

Your C++ compiler generates a copy constructor for you by default! That's pretty handy, but causes problems with pointer members. In your example, remember that int *myArray is just a memory address; when the value of myArray is copied from the old object to the new one, you'll now have two objects pointing to the same array in memory. This isn't intrinsically bad, but the destructor will then try to delete the same array twice, hence the "double free or corruption" runtime error.

第一步是实现一个 copy构造器,它可以安全地将数据从一个对象复制到另一个对象。为简单起见,它可能看起来像这样:

The first step is to implement a copy constructor, which can safely copy the data from one object to another. For simplicity, it could look something like this:

Test(const Test& other){
    myArray = new int[10];
    memcpy( myArray, other.myArray, 10 );
}

现在,当您复制测试对象时,将为该对象分配一个新数组

Now when you're copying Test objects, a new array will be allocated for the new object, and the values of the array will be copied as well.

不过,我们还没有完全摆脱麻烦。编译器为您生成的另一种方法可能会导致类似的问题-分配。区别在于分配时,我们已经有一个现有对象,其内存需要适当地管理。以下是基本的赋值运算符实现:

We're not completely out trouble yet, though. There's another method that the compiler generates for you that could lead to similar problems - assignment. The difference is that with assignment, we already have an existing object whose memory needs to be managed appropriately. Here's a basic assignment operator implementation:

Test& operator= (const Test& other){
    if (this != &other) {
        memcpy( myArray, other.myArray, 10 );
    }
    return *this;
}

这里的重要部分是我们从另一个数组中复制数据放入此对象的数组中,使每个对象的内存分开。我们也有一份自我分配支票;否则,我们会从自己复制到自己,这可能会引发错误(不确定该怎么做)。如果我们要删除并分配更多的内存,自我分配检查会阻止我们删除需要复制的内存。

The important part here is that we're copying the data from the other array into this object's array, keeping each object's memory separate. We also have a check for self-assignment; otherwise, we'd be copying from ourselves to ourselves, which may throw an error (not sure what it's supposed to do). If we were deleting and allocating more memory, the self-assignment check prevents us from deleting memory from which we need to copy.

这篇关于队列:: push之后加倍释放或损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆