我正在编写一个动态数组类。我包含了一个复制构造函数和operator =函数,允许我将一个数组分配给另一个数组。当我为彼此分配相同长度的数组时它起作用,但是当它们具有不同的长度时,我得到编译器内存警告和/或代码炸弹而不执行,这取决于左手数组是否大于右手数组,反之亦然。我有一个向数组插入值的函数,并认为这个问题可能在这里(注意:我必须在析构函数中注释掉内存删除以获取代码)。
class Array
{
private:
int * ptr;
int size;
int numElement;
public:
Array();
Array(const int*, int);
Array(const Array&);
~Array();
void setValueAtIndex(int, int);
void insertValueAtEnd(int );
int getArraySize();
const Array& operator=(const Array& );
};
#include "array.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
Array::Array()
{
size = 10;
numElement = 0;
ptr = new int[size];
for (int i = 0; i < size; ++i)
{
ptr[i] = 0;
}
}
Array::Array(const int * ptr_, int size_)
{
size = size_;
numElement = size;
ptr = new int[numElement];
for (int i = 0; i < size; ++i)
{
ptr[i] = ptr_[i];
}
}
Array::Array(const Array& other)
{
size = other.size;
numElement = other.numElement;
if (other.ptr)
{
ptr = new int[numElement];
for(int i = 0; i < size; ++i)
{
ptr[i] = other.ptr[i];
}
if(!ptr)
{
exit(EXIT_FAILURE);
}
}
else ptr = 0;
}
Array::~Array()
{
if(ptr)
{
//delete [] ptr;
//ptr = 0;
}
}
void Array::setValueAtIndex(int a, int b)
{
if(b > size)
{
exit(EXIT_FAILURE);
}
ptr[b] = a;
}
void Array::insertValueAtEnd(int insert)
{
if(numElement == size)
{
size++;
}
ptr[size-1] = insert;
numElement++;
}
int Array::getArraySize()
{
return size;
}
const Array& Array::operator=(const Array& other)
{
if(this != &other)
{
if (ptr)
{
delete [] ptr;
ptr = 0;
}
numElement = other.numElement;
size = other.size;
if(other.ptr)
{
ptr = new int[numElement];
for(int i = 0; i < size; ++i)
{
ptr[i] = other.ptr[i];
}
}
else ptr = 0;
}
return *this;
}
答案 0 :(得分:1)
您的代码存在多个问题!从复制构造函数中的次要构件开始:如果new T[n]
失败,则不返回0
。相反,它抛出和异常。因此,永远不会达到您的测试if (!ptr)
。在你的代码中,因为你已经使用了指针,所以太迟了!
赋值运算符完全乱码!使用自我分配检查通常是一个非常好的迹象,表明代码不是异常安全的(如果没有这种检查,真正的自我分配将无法工作),或者您正在针对罕见情况进行优化(希望您不要将对象更频繁地分配给自己而不是其他对象。在您的情况下,检查表明代码,如果它正在工作,将不会是异常安全:您开始删除内存,如果分配内存失败并抛出您无法获取。可能导致您悲伤的主要错误是您分配numElements
个对象(这似乎是数组中元素的数量,而不是其容量)但是您复制了size
个对象(这似乎是数字)可能的元素,即numElements < size
)。作为旁注,我强烈建议您使用与标准C ++库相同的名称作为其容器,即size()
表示实际元素的数量,capacity()
表示保留空间的元素数量。
所有这一切,实现赋值运算符的最佳方法是利用已经为复制构造函数和析构函数完成的工作:这些已经知道如何复制对象以及如何去除对象。这样做的方式如下:
Array& Array::operator= (Array other) {
this->swap(other);
return *this;
}
void Array::swap(Array& other) {
std::swap(this->ptr, other.ptr);
std::swap(this->size, other.size);
std::swap(this->numElements, other.numElements);
}
这种方法要求还有一个函数swap()
,可以交换该类型的两个对象。但是,编写通常是微不足道的:您只需std::swap()
每个成员。
答案 1 :(得分:0)
您的代码使用insertValueAtEnd()中断,因为它不会增加底层数组的大小。这个简单的测试案例让我崩溃了:
int realarr[] = { 1,2,3};
Array arr1(realarr, 3);
arr1.insertValueAtEnd(7);
您需要检查是否已达到容量(您称之为大小)并增加底层存储(如果是这样)。
我假设您正在实施动态数组?
如果您愿意,可以忽略一个样式问题。将name_用作类数据成员并将名称作为参数传递更为常见。