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);
}

运行此程序后,我收到运行时错误“双重释放或损坏”。如果我摆脱了析构函数内容(delete),它就可以正常工作。怎么了?

最佳答案

让我们谈谈在 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;
}

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

https://stackoverflow.com/questions/14063791/

相关文章:

c++ - 为什么优化会杀死这个功能?

c++ - C++ 中的 vector ::size_type

c++ - 每个类都应该有一个虚拟析构函数吗?

c++ - 使用 Qt 进行序列化

>' should be ` > >' within ">c++ - 模板内的模板 : why "` >>' should be ` > >' within

c++ - 是否有可以解析 C++ 的优秀 Python 库?

c++ - 如何在 GCC 搜索路径中包含头文件?

c++ - 内存分配是系统调用吗?

c++ - C中有const吗?

c++ - 在 std::map 中更改元素键的最快方法是什么