Delete[] 导致 C++ 崩溃

Delete[] causing crash in C++

我正在使用此 中的相同代码,但我进行了一些更改。我的问题是我有一个动态数组,我在复制构造函数的运算符重载内部调用了 delete[],但出现以下错误。

在 Lab3.exe 中的 0x0F7063BB (ucrtbased.dll) 抛出异常:0xC0000005:访问冲突读取位置 0xCCCCCCBC。

如果有这个异常的处理程序,程序可以安全地继续。

谁能帮我理解为什么? 我检查了相关问题,但存在与我所看到的不同的错误,而且我在 google 搜索中没有找到结果。我在 visual studio 2015 年使用 C++ 11。

#include "ListArray.h"

template < typename DataType >
List<DataType>::List ( int maxNumber )
{
    //maxSize = MAX_LIST_SIZE; maybe???
    maxSize = maxNumber;
    dataItems = new DataType[maxSize];
    size = maxSize - 1;
    cursor = 0; // sets cursor to the first value in list
    for (; cursor <= size; cursor++)
        dataItems[cursor] = 1;
    cursor = 0;
}

template < typename DataType >
List<DataType>::List ( const List& source )
{
    *this = source; // should be handled by copy constructor
}

template < typename DataType >
List<DataType>& List<DataType>::operator= ( const List& source )
{
    if (this != &source)
    {
        maxSize = source.maxSize;
        size = source.size;
        cursor = source.cursor;
        delete []dataItems; // clears dataItems, weird run-time error here. Why? 
        dataItems = new DataType[size];
        for (int count = 0; count < size; count++)
            dataItems[count] = source.dataItems[count];
    }
    else
        // do nothing, they are the same so no copy is made
        return *this;
}

template < typename DataType >
List<DataType>::~List ()
{
    maxSize = 0;
    size = 0;
    cursor = -1;
    delete[] dataItems;
}

编辑: 我最初 post 编辑了其他几个不完整的函数,它们也是我正在尝试构建的程序的一部分。我的意思是只包括那些我知道会产生我的问题的。我为不好的地方道歉 post.

复制构造函数不会在 class 的新实例中初始化任何内容。它所做的只是调用赋值运算符。

赋值运算符执行:

delete []dataItems;

由于 dataItems 尚未初始化,这会导致未定义的行为,并立即崩溃。

如果您要使用赋值运算符来制作副本,则需要一个空对象作为开始,否则 operator= 在替换旧内容之前尝试清理旧内容时会严重失败(正如 Sam 在他的回答中解释的和 MikeCAT 在他的评论中提到的——给他们投票——以及 )。

从 C++11 开始,构造函数链接也称为构造函数委托是可能的,如下所示:

template < typename DataType >
List<DataType>::List ( const List& source )
    : List() /* default construct object before proceeding */
{
    *this = source; // should be handled by copy constructor
}

另一种选择是让复制构造函数自己负责创建默认对象,这正是 C++98 和 C++03 所需要的:

template < typename DataType >
List<DataType>::List ( const List& source )
    : maxSize(0), dataItems(NULL), size(0) // initialize members
{
    *this = source; // should be handled by copy constructor
}

但这是在复制默认构造函数的功能,因此只要您的编译器支持 C++11 功能,最好调用现有构造函数。

构造函数委托的细节……变得复杂了。除其他事项外,通常从对象构造函数内部抛出的任何异常都会阻止对象永远存在,并且不会调用析构函数。当使用委托时,对象在任何构造函数完成时变为活动状态,包装构造函数内的异常将面对一个已经活动的对象并为您调用析构函数。这种行为可能是合意的,也可能不是合意的,但它是需要注意的,因为异常安全在现代 C++ 中很重要。