【问题标题】:Using delete[] in a destructor: Invalid address specified to RtlValidateHeap在析构函数中使用 delete[]:指定给 RtlValidateHeap 的地址无效
【发布时间】:2017-04-10 20:04:03
【问题描述】:

我正在编写一个数组类模板,但析构函数有问题。

#ifndef ARRAY_CPP
#define ARRAY_CPP
using namespace std;
#include<iostream>
#include<sstream>
#include "Array.h"


//Define default constructor, initialize an array of size 10 with all elements being (0,0)
template<typename T> //Define type parameter
Array<T>::Array() {
    size = 10;
    m_data = new T[size];
}


template<typename T> //Define type parameter
Array<T>::Array(int si) {
    size = si;
    m_data = new T[size];
}

template<typename T> //Define type parameter
Array<T>::Array(const Array<T>& source) {
    size = source.size; //Set the size equal to the size of the source
    m_data = new T[size]; //Create a new source on the heap
    //Loop through and copy each member of the source array to the new array
    for (int i = 0; i < size; i++) {
        m_data [i] = source.m_data [i];
    }
}

//Define default destructor
template<typename T> //Define type parameter
Array<T>::~Array() {
        delete[] m_data;
    }

    //Define operator =
template<typename T> //Define type parameter
Array<T>& Array<T>::operator = (const Array<T>& source) {
    //Check self-assignment
    if (this != &source) {
        //Delete the old array
        delete[] m_data;
        size = source.size; //Set the size equal to the size of the source
        m_data = source.m_data; //Set the dynamic C array equal to that of the source
        //Loop through each element and copy each member of the source array to the current array
        for (int i = 0; i < size; i++) {
            m_data[i] = source.m_data [i];

        }
    }
    //Return current array
    return *this;

}
//Define operator[]
template<typename T> //Define type parameter
T& Array<T>::operator[](int index) {
    if ((index < 0) || (index>= size))
        throw -1;
    return m_data[index];
}

//Define constant operator[]
template<typename T> //Define type parameter
const T& Array<T>::operator [] (int index) const {
    if ((index < 0) || (index >= size))
        throw -1;
    return m_data[index];
}

using namespace std;
#include<iostream>
#include<sstream>
#include "Array.cpp"


void main() {

    Array<double> test(10);
    Array<double> test2(10);
    test2 = test;
}

每当在 main 中调用数组的析构函数时,它都会给我错误:指定给 RtlValidateHeap 的地址无效。我知道这是因为我试图删除堆栈上的内存。但是,在我的构造函数中,我使用 new 初始化数组,这应该在堆上创建内存......在我实现模板之前代码运行良好。非常感谢!

【问题讨论】:

  • 你能举一个完整的例子来说明这个问题吗?添加您需要添加的最简单的main 以演示问题,并显示完整的错误。您的类定义也不完整。试着让你的类完整并给出一个 main,并删除演示示例不需要的任何方法(例如,你可能不需要两个构造函数)。
  • 1) 在析构函数中调用delete[] 时无需检查NULL。 2)您的赋值运算符存在很大缺陷。 3) 你的main 函数在哪里? 4) 为什么在数组标题中包含Point.h
  • 我注意到您在头文件和源文件中拆分模板代码。 You might want to rethink that
  • m_data = source.m_data; 应该是m_data = new T[size];(对于构造函数)。

标签: c++


【解决方案1】:

我可以看到一个错误和一个潜在错误:

错误:在赋值运算符中。您复制指针value

template<typename T>
Array<T>& Array<T>::operator = (const Array<T>& source) {
        // STUFF

        // This is a problem
        m_data = source.m_data;

        // MORE STUFF
    }
    return *this;

}

您现在有两个对象指向同一块动态分配的内存。这是一个问题,因为当它们超出范围时,两个对象中的析构函数都会尝试在同一个指针 value 上调用 delete。

潜在错误:我没有看到复制构造函数。如果您没有定义一个(或没有明确删除它),那么编译器将为您生成它。默认值不适用于拥有的资源(即动态分配的内存),因为它是资源的浅拷贝。

编译器生成的如下所示:

template<typename T>
Array<T>& Array<T>::Array(const Array<T>& source)
    : size(source.size)
    , m_data(source.m_data)
{}

您可以看到这与您的赋值运算符有相同的问题。它只是复制指针value。导致两个对象指向同一动态分配的内存的相同问题。

【讨论】:

  • 我认为你的意思是 m_data = source.m_data; 解决这个问题
  • @haozzzzz:是的。但还有更多改进的方法。您应该在codereview.stackexchange.com 获得代码审查
猜你喜欢
  • 2015-10-15
  • 1970-01-01
  • 2020-05-04
  • 1970-01-01
  • 2016-07-13
  • 2020-08-10
  • 1970-01-01
  • 2014-11-22
  • 2018-06-02
相关资源
最近更新 更多