其他分享
首页 > 其他分享> > c – queue :: push后双重释放或损坏

c – queue :: 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);
}

运行此操作后,我收到运行时错误“double free or corruption”.如果我摆脱了析构函数内容(删除),它可以正常工作.怎么了?

解决方法:

我们来谈谈用C复制对象.

Test t;,调用默认构造函数,该构造函数分配一个新的整数数组.这很好,你的预期行为.

使用q.push(t)将t推入队列时出现问题.如果您熟悉Java,C#或几乎任何其他面向对象的语言,您可能希望将您创建的对象添加到队列中,但C不会以这种方式工作.

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

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

我如何解决它?

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

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

现在,当您复制Test对象时,将为新对象分配一个新数组,并且还将复制该数组的值.

不过,我们还没有彻底摆脱困境.编译器为您生成的另一种方法可能会导致类似的问题 – 分配.不同之处在于,通过赋值,我们已经有了一个现有对象,其内存需要进行适当的管理.这是一个基本的赋值运算符实现:

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

这里的重要部分是我们将数据从另一个数组复制到这个对象的数组中,保持每个对象的内存分离.我们还检查自我分配;否则,我们会从自己复制到自己,这可能会引发错误(不确定它应该做什么).如果我们删除并分配更多内存,则自我分配检查会阻止我们删除需要复制的内存.

标签:c,runtime-error,delete-operator
来源: https://codeday.me/bug/20190917/1809121.html