我正在尝试用c ++实现动态数组。一旦它变满,它的大小加倍并被复制到双倍大小的数组。 看起来不错,但Valgrind说我有泄漏。 我应该说我不允许使用任何c ++ STL结构 - 这就是我使用new []和delete []运算符的原因。
这是我的代码:
[ 96%] Linking CXX executable mangosd
../game/libgame.a(Map.cpp.o): In function `sh_hashtable_settings<ObjectGuid, std::tr1::hash<ObjectGuid>, unsigned long, 4>::hash(ObjectGuid const&) const':
/usr/include/google/sparsehash/hashtable-common.h:65: undefined reference to `std::tr1::hash<ObjectGuid>::operator()(ObjectGuid) const'
collect2: error: ld returned 1 exit status
src/mangosd/CMakeFiles/mangosd.dir/build.make:244: recipe for target 'src/mangosd/mangosd' failed
make[2]: *** [src/mangosd/mangosd] Error 1
CMakeFiles/Makefile2:930: recipe for target 'src/mangosd/CMakeFiles/mangosd.dir/all' failed
make[1]: *** [src/mangosd/CMakeFiles/mangosd.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
我的主要计划是:
template<class T>
class DynamicArray
{
int size;
int numOfElements;
T* arr;
public:
DynamicArray(int size) :
size(size), numOfElements(0)
{
arr = new T[size];
}
;
int getSize()
{
return size;
}
int getNumberOfElements()
{
return numOfElements;
}
void insert(T element)
{
arr[numOfElements++] = element;
if (numOfElements == size)
{
T* extended_array = new T[size * 2];
for (int i = 0; i < numOfElements; i++)
{
extended_array[i] = arr[i];
}
delete[] arr;
arr = extended_array;
size = size * 2;
}
}
T& operator[](int i)
{
if (!((i >= 0) && (i < size)))
throw arrayOutOfBoundsException();
return arr[i];
}
~DynamicArray()
{
delete[] arr;
}
class arrayOutOfBoundsException: std::exception
{
};
};
** valgrind在将析构函数编译为注释时显示此错误:
using std::cout;
using std::endl;
void printIntArray(DynamicArray<int> arr){
cout << "size: " << arr.getSize() << "; " << "numOfElemnts: " << arr.getNumberOfElements() << endl;
cout << "array: ";
for(int i=0; i<arr.getNumberOfElements(); i++){
cout << " " << arr[i];
}
cout << endl << endl;
}
int main() {
DynamicArray<int> arr(5);
printIntArray(arr);
arr.insert(1);
arr.insert(2);
arr.insert(3);
printIntArray(arr);
arr.insert(4);
printIntArray(arr);
arr.insert(5);
printIntArray(arr);
arr.insert(6);
printIntArray(arr);
arr.insert(7);
arr.insert(8);
arr.insert(9);
printIntArray(arr);
arr.insert(16);
printIntArray(arr);
arr[9] = 901;
arr[0] = 101;
printIntArray(arr);
有谁能告诉我我做错了什么?我在滥用“删除[]”吗?还是析构函数?
感谢
答案 0 :(得分:3)
提问者描述的行为是不可能的或
将析构函数编译为注释:
表示析构函数已被注释掉,这导致泄漏。这已经在评论中得到证实。没有destuctor,最后的分配永远不会被放弃。
短版本是这样的:
如果一个类需要用户定义的复制构造函数,赋值运算符或析构函数,它几乎总是需要这三个。
有关此内容的更多信息:What is The Rule of Three?
在这种情况下,
void printIntArray(DynamicArray<int> arr)
按值接受arr
。这意味着arr是传入的值的副本。如果没有自定义复制构造函数,arr
内的printIntArray
将指向与源相同的分配。该副本将在printIntArray
结束时销毁,析构函数将删除该分配,使源指向无效内存,因此......
DynamicArray<int> arr(5); // allocated storage inside arr
printIntArray(arr); // made a copy of arr that points to same storage.
// Storage freed when copy destroyed
arr.insert(1); // invokes undefined behaviour writing into invalid memory
arr.insert(2); // same
arr.insert(3); // same
printIntArray(arr); // copies arr again. This copy is pointing to the same invalid memory
// and will try to free the allocation a second time when the
// copy is destroyed
该程序几乎肯定会崩溃,因此无法从用户代码中泄露。但是因为程序崩溃了,Crom只知道运行时正在使用的幕后结构没有正确放弃。
无论发生什么,从
开始arr.insert(1);
该程序深入Undefined Behaviour,之后发生的任何事情都是任何人的猜测。内存泄漏是您最不担心的事情。
实现复制构造函数和赋值运算符(We'll ignore the Rule of Five for now.)
你可以改变
void printIntArray(DynamicArray<int> arr)
通过引用传递
void printIntArray(DynamicArray<int> & arr)
然后
DynamicArray(const DynamicArray &) = delete;
DynamicArray& operator=(const DynamicArray &) = delete;
并禁用所有复制,但这看起来有点严厉。
取而代之的是lets use Copy and Swap,因为它简单易懂。请注意,它也可能效率低下,因此并不总是正确的工具。这符合我们想要的。
DynamicArray(const DynamicArray & src) :
size(src.size), numOfElements(src.numOfElements), arr(new T[size])
{
for (int i = 0; i < numOfElements; i++)
{
arr[i] = src.arr[i];
}
}
DynamicArray& operator=(const DynamicArray src)
{
std::swap(size, src.size);
std::swap(numOfElements, src.numOfElements);
std::swap(arr, src.arr);
return *this;
}
因为谁想要复制,他们不需要我们仍然
void printIntArray(DynamicArray<int> & arr)
我们一旦完成测试,复制构造函数就能正常工作。