【问题标题】:Heap Corruption error with Copy constructor and overloaded assignment operator复制构造函数和重载赋值运算符的堆损坏错误
【发布时间】:2023-03-29 11:32:02
【问题描述】:

我是一名学生,因此对于没有使用正确的论坛协议,我深表歉意。我已经在这个问题上搜索了几个小时,我的同学都无法提供帮助。我的任务是在 C++ 中创建一个复制构造函数、重载赋值运算符 (=) 和一个析构函数(“三巨头”)来管理堆上的数组。我在 VS13 中写的下面的内容产生了正确的输出,但出现了调试错误: HEAP CORRUPTION DETECTED: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.
}

【问题讨论】:

    标签: c++ constructor


    【解决方案1】:

    您的代码存在一些问题。首先,您在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

    作为旁注,您实际上不需要在析构函数中将NULL 分配给arrayPointer。一旦对象被销毁,它就消失了,任何事后访问它的尝试都会导致未定义的行为。

    【讨论】:

    • 您的建议奏效了!你是救生员,谢谢!我应该将此帖子标记为“已回答”吗?我该怎么做?
    • 是的,如果某个答案解决了您的问题,那么您应该通过单击答案左上角的复选框将其标记为已接受。如果有多个答案有帮助,则由您决定哪个答案值得被接受。如果您想给贡献者一点奖金,也可以对答案进行投票。
    【解决方案2】:

    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 的值而不是引用来进一步优化,如链接页面中所述。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-12
      • 2019-11-23
      • 2013-10-23
      • 2012-03-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      相关资源
      最近更新 更多