我正在使用此code from my previous SO post中的相同代码,但我做了一些更改。我的问题是我有一个动态数组,我在我的运算符重载内部为复制构造函数调用delete[]
,我得到下面的错误。
Lab3.exe中0x0F7063BB(ucrtbased.dll)抛出异常:0xC0000005:访问冲突读取位置0xCCCCCCBC。
如果存在此异常的处理程序,则可以安全地继续该程序。
任何人都可以帮我理解为什么吗? 我检查了相关的问题,但有不同的错误,而不是我看到的,我没有在谷歌搜索中找到结果。我在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;
}
编辑:我最初发布了其他几个不完整的函数,也是我正在尝试构建的程序的一部分。我的意思是只包括我知道正在产生问题的那些。我为糟糕的帖子道歉。
答案 0 :(得分:2)
复制构造函数不会初始化类的新实例中的任何内容。它只是调用赋值运算符。
赋值运算符执行:
delete []dataItems;
由于dataItems
尚未初始化,因此导致未定义的行为,并立即崩溃。
答案 1 :(得分:2)
如果您要使用赋值运算符来制作副本,则需要一个空对象,否则operator=
会在替换之前尝试清理旧内容时失败。 (正如Sam在他的回答中所解释的那样,MikeCAT在他的评论中提到 - 给他们起来投票 - 以及Dieter told you on your earlier question)。
从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 ++中很重要。