2014-12-08 121 views
0

我是一名学生,所以我前面道歉,不使用正确的论坛协议。我已经在这个问题上搜寻了几个小时,我的同学们都无法提供帮助。我的任务是在C++中创建一个拷贝构造函数,重载赋值操作符(=)和析构函数('三个')来管理堆中的数组。我在VS13中写下的内容会产生正确的输出,但我得到一个调试错误:检测到堆损坏:C++ crt检测到应用程序在堆缓冲区结束后写入内存 任何人都可以给我一些指导,我甚至不会知道在哪里看。谢谢!!复制构造函数和重载赋值运算符堆损坏错误

//copy constructor 

myList::myList(const myList& source){ 
cout << "Invoking copy constructor." << endl; 
array_capacity = source.array_capacity; //shallow copy 
elements = source.elements; //shallow copy 
delete[] arrayPointer; 
arrayPointer = new double(source.array_capacity); //deep copy 

for (int i = 0; i < array_capacity; i++) //copy array contents 
    { 
     arrayPointer[i] = source.arrayPointer[i]; 
    } 
} 

//overloaded assignment operator 
myList& myList::operator=(const myList& source){ 

cout << "Invoking overloaded assignment." << endl; 

if (this != &source){ 

array_capacity = source.array_capacity; //shallow copy 

elements = source.elements; //shallow copy 

delete[] arrayPointer; //delete original array from heap 

arrayPointer = new double(array_capacity); //deep copy 

for (int i = 0; i < source.array_capacity; i++) {//copy array contents 
    arrayPointer[i] = source.arrayPointer[i]; 
     } 
    } 
return *this; 
} 

//destructor 
myList::~myList(){ 

cout << "Destructor invoked."<< endl; 

delete[] arrayPointer; // When done, free memory pointed to by myPointer. 

arrayPointer = NULL; // Clear myPointer to prevent using invalid memory reference. 
} 

回答

2

您的代码有几个问题。首先,您在arrayPointer上调用delete,但它尚未初始化为任何内容。事实上,这可能最终会删除已分配的内存,或导致实施delete中的例外或资产。第二次初始化时,您将分配一个初始化为source.array_capacity的值double。注意下面一行中使用的括号。

arrayPointer = new double(source.array_capacity); 

这样肯定会导致在复制过程中出现未定义的行为,因为最终访问数组边界之外的元素。上面一行是存在于你的拷贝构造函数和拷贝赋值运算符,应该用方括号,而不是像这样:

arrayPointer = new double[source.array_capacity]; 

你也从来没有检查,看看是否有存储在myListsource实例的任何元素。在这种情况下,您应该将nullptr(或C++ 03中的NULL)分配到arrayPointer

作为一个附注,你并不需要在你的析构函数中指定NULLarrayPointer。一旦对象被销毁,它就消失了,任何在事后访问它的尝试都会导致未定义的行为。

+0

你的建议奏效!你是一个拯救生命的人,谢谢!我是否应该将此帖标记为“已回答”?我怎么做? – 2014-12-08 02:37:59

+0

是的,如果答案解决了您的问题,那么您应该通过点击答案左上角的复选框将其标记为已接受。如果有多个答案有帮助,那么由您来决定哪一个答案值得接受。如果您想给贡献者一点红利,您也可以提出答案。 – 2014-12-08 02:43:44

1

Captain Obvlious已经指出你的拷贝构造函数存在这个问题。

您将会注意到,复制构造函数和赋值运算符包含许多相同的代码,但有细微的差别。事实上,这可能是你如何以错误结束(赋值运算符需要delete[]旧值,但复制构造函数没有。

代码重复是不好的,因为它会导致像这样的微妙错误蔓延你可以在这里使用一个很好的模式是所谓的copy and swap idiom

的要点是你定义的拷贝构造函数,你还可以定义swap。那么你得到免费的分配。这工作,因为swap更容易实现它比赋值运算符正确,另一个主要好处是没有任何问题可以出错(您不必担心内存不足错误等)。

在你的代码中;让您的固定拷贝构造函数,你可以添加类定义:

friend void swap(myList &a, myList &b) 
{ 
    std::swap(a.array_capacity, b.array_capacity); 
    std::swap(a.arrayPointer, b.arrayPointer); 
    std::swap(a.elements, b.elements); 
} 

现在赋值运算符是非常简单的:

myList& myList::operator=(const myList &source) 
{ 
    myList temp(source); 
    swap(*this, temp); 
    return *this; 
} 

从当前对象旧的资源由析构函数删除temp。此版本甚至不需要检查自我分配,因为std::swap(x, x)已定义良好。

如链接页面所述,甚至可以通过按值取代source来进一步优化这一点。

相关问题