C++ &引用;“双重自由或腐败”;实现动态数组数据结构时出错
我试图为我的数据结构和算法课程实现一个动态数组数据结构,但我认为我在内存管理方面遇到了一些问题。我的模板类如下所示 ArrayList.hC++ &引用;“双重自由或腐败”;实现动态数组数据结构时出错,c++,memory-management,destructor,dynamic-arrays,C++,Memory Management,Destructor,Dynamic Arrays,我试图为我的数据结构和算法课程实现一个动态数组数据结构,但我认为我在内存管理方面遇到了一些问题。我的模板类如下所示 ArrayList.h #include <iostream> #include <cstring> using namespace std; #define Length(array) (sizeof((array))/sizeof((array[0]))) template <class T> class ArrayList { p
#include <iostream>
#include <cstring>
using namespace std;
#define Length(array) (sizeof((array))/sizeof((array[0])))
template <class T>
class ArrayList
{
public:
ArrayList() {a = new T[1]; n = 0;}
~ArrayList() {delete [] a;}
int size();
int backingSize();
T get(int i);
T set(int i, T x);
void add(int i, T x);
T remove (int i);
private:
void resize();
T *a;
int n;
};
template <class T>
int ArrayList<T>::size() { return n; }
template <class T>
int ArrayList<T>::backingSize() { return Length(a); }
template <class T>
T ArrayList<T>::get(int i) { return a[i]; }
template <class T>
T ArrayList<T>::set(int i, T x)
{
T temp = a[i];
a[i] = x;
return temp;
}
template <class T>
void ArrayList<T>::add(int i, T x)
{
if (n+1 > Length(a)) resize();
for (int j = n; j > i; j--) a[j] = a[j-1];
a[i] = x;
n++;
}
template <class T>
T ArrayList<T>::remove(int i)
{
T temp = a[i];
for (int j = i; j < n-1; j++) a[j] = a[j+1];
n--;
if (Length(a) > 3*n) resize();
return temp;
}
template <class T>
void ArrayList<T>::resize()
{
if ( n+1 > Length(a))
{
cout << "Making Bigger\n";
T* tempArr = new T[2*n];
memcpy(tempArr, a, n * sizeof(T));
delete [] a;
a = tempArr;
}
else // (Length(a) > 3*n)
{
cout << "Making Smaller\n";
T* tempArr = new T[n/2];
memcpy(tempArr, a, n * sizeof(T));
delete [] a;
a = tempArr;
}
}
它似乎按照预期工作,get函数在其索引处返回正确的值,size函数返回正确的数组长度,并且它们没有seg错误。但是,
backingSize()
函数总是返回2,并且我认为最后抛出的错误与糟糕的内存管理有关。我已经被难住了很长一段时间,所以如果有任何帮助,我将不胜感激。您永远不应该在指针上使用#定义长度(数组)(sizeof((数组))/sizeof((数组[0]))
。无法从指针知道数组的大小。这可能会导致你的问题。既然您有一个类,为什么不将大小和容量存储为变量呢?在处理数组类型的对象时,内存中占用的8个字节的大小和容量实际上什么都不是。您显式地调用对象的析构函数。析构函数是自动调用的,因此由于您已经调用了析构函数,因此会发生双重自由错误
要了解何时调用析构函数,请查看此这里有一个bug(不确定是否没有其他bug):
tempArr
只能保存n/2
元素,但您尝试将n
元素复制到其中。这是未定义的行为。此外,不可能为所有可能的类型逐字节复制元素T
您还应该为您的类型定义一个复制构造函数、赋值运算符和移动赋值运算符(或删除它们)。首先使用调试器来确定您可能在何处点击delete[]
两次?不要显式调用析构函数-当变量离开作用域时会自动调用它。memcpy(tempArr,a,n*sizeof(t))代码>如果T
为非POD类型,则此功能将无法正常工作。例如,如果T
是std::string
,则此代码会导致未定义的行为。你的代码有很多错误,它超出了学习“数据结构和算法”的范围。C++不适合学习普通的“数据结构和算法”,除非你知道语言的所有细微差别。对于第一个,我的意思是它是两个以上的支持数组的长度。谢谢我不确定我是否完全理解你的第二部分。你是说memcpy()不能用于所有类型,但它在我的情况下可以工作,因为我正在使用int进行测试?@jasper它适用于int
,因为int
是可复制的。
#include "ArrayList.h"
#include <iostream>
using namespace std;
int main()
{
ArrayList <int> myList;
cout << myList.size() << "\n\n";
myList.add(0,15);
cout << myList.get(0) << ", " << myList.size() << ", " << myList.backingSize() << "\n";
myList.add(1,34);
cout << myList.get(1) << ", " << myList.size() << ", " << myList.backingSize() << "\n";
myList.add(2,23);
cout << myList.get(2) << ", " << myList.size() << ", " << myList.backingSize() << "\n";
myList.add(3,1);
cout << myList.get(3) << ", " << myList.size() << ", " << myList.backingSize() << "\n\n";
myList.~ArrayList();
}
15, 1, 2
34, 2, 2
Making Bigger
23, 3, 2
Making Bigger
1, 4, 2
*** Error in `./TestArrayList': double free or corruption (fasttop): 0x000000000090c010 ***
Aborted
T* tempArr = new T[n / 2]; // the size is n / 2
memcpy(tempArr, a, n * sizeof(T)); // but here you try to copy n elements