动态分配数组的析构函数导致堆缓冲区错误
Destructor of dynamically allocated array causing Heap buffer error
所以我有一个作业要编写一个版本的矢量库而不使用它。我需要使用动态分配的数组,但是它们的析构函数导致错误。这是我的代码:
class orderedVector {
friend ostream& operator<<(ostream&, const orderedVector&);
friend istream& operator>>(istream&, orderedVector&);
public:
orderedVector(int = 9);
~orderedVector();
int getSize() const;
int getCapacity() const;
void doubleCapacity();
bool find(int) const;
void insert(int);
void remove(int);
void findSum(int);
private:
int size;
int capacity;
int* ptr;
};
orderedVector::orderedVector(int c) {
capacity = c;
size = 0;
ptr = new int[c];
}
orderedVector::~orderedVector() {
delete[] ptr;
}
int orderedVector::getSize() const {
return size;
}
int orderedVector::getCapacity() const {
return capacity;
}
void orderedVector::doubleCapacity() {
int newCapacity = capacity * 2;
orderedVector temp(capacity);
for (int i = 0; i < size; i++) {
temp.ptr[i] = ptr[i];
}
ptr = new int[newCapacity];
for (int i = 0; i < size; i++) {
ptr[i] = temp.ptr[i];
}
capacity = newCapacity;
}
bool orderedVector::find(int number) const {
for (int i = 0; i <= size; i++)
if (number == ptr[i])
return true;
return false;
}
void orderedVector::insert(int number){
if (find(number)) {
return;
}
if (size == capacity)
doubleCapacity();
if (size == 0)
ptr[0] = number;
else {
int checkpoint = size;
for (int i = 0; i < size; i++) {
if (number < ptr[i]) {
checkpoint = i;
break;
}
}
for (int i = size-1; i >= checkpoint; i--) {
ptr[i + 1] = ptr[i];
}
ptr[checkpoint] = number;
}
size++;
}
void orderedVector::remove(int number) {
if (find(number) == false)
cout << "Number does not exist in the vector.\n";
else {
int checkpoint = 0;
for (int i = 0; i <= size; i++)
if (ptr[i] == number)
checkpoint = i;
for (int i = checkpoint; i < size; i++)
ptr[i] = ptr[i + 1];
}
ptr[size] = 0;
size--;
}
void orderedVector::findSum(int number) {
for (int i = 0; i <= size; i++) {
for (int j = i+1; j <= size; j++) {
if (ptr[i] + ptr[j] == number) {
cout << "The two numbers that have a sum of " << number
<< " are " << ptr[i] << " and " << ptr[j] << endl;
return;
}
}
}
cout << "No two numbers found that give a sum of " << number << endl;
}
ostream& operator<<(ostream& output, const orderedVector& vector) {
for (int i = 0; i < vector.size; i++)
output << vector.ptr[i] << " ";
output << endl;
return output;
}
istream& operator>>(istream& input, orderedVector& vector) {
int x = 0;
for (int i = 0; i < vector.capacity; i++) {
input >> x;
vector.insert(x);
}
return input;
}
似乎当我初始化一个元素,并且数组被完全填充时,我得到这个错误:
检测到堆损坏,CRT 检测到应用程序在堆缓冲区结束后写入内存。
我知道它是析构函数,因为当我删除它时,没有发生任何错误。
另外,当我的向量元素没有完全填满时(容量大于大小),也不会出现错误。
我想知道如何解决这个问题,或者删除运算符的一般工作方式,以及为什么在我填充动态创建的数组时会导致错误。
动态分配最多只能释放一次。因此,当您在析构函数中解除分配时,建立一个 class 不变性很重要,该不变性至多一个实例唯一拥有相同的指针。如果违反了这种不变量,那么这些实例的析构函数可能会尝试 delete
相同的指针两次,这会导致未定义的行为。哪个不好。
您的 class orderedVector
确实在其析构函数中解除了分配。但是,class 的(隐式生成的)复制构造函数复制成员变量,这违反了唯一所有权的 class 不变量。
您未能提供 MCVE,但有理由猜测您的程序复制了 orderedVector
的实例,导致由于多个 delete
而导致未定义的行为相同的指针。
解决方案是使 class 不可复制和不可移动,或者遵循 3(或 5)规则,即以某种方式实现复制(和移动)构造函数和赋值运算符强制执行唯一所有权的不变性。
所以我有一个作业要编写一个版本的矢量库而不使用它。我需要使用动态分配的数组,但是它们的析构函数导致错误。这是我的代码:
class orderedVector {
friend ostream& operator<<(ostream&, const orderedVector&);
friend istream& operator>>(istream&, orderedVector&);
public:
orderedVector(int = 9);
~orderedVector();
int getSize() const;
int getCapacity() const;
void doubleCapacity();
bool find(int) const;
void insert(int);
void remove(int);
void findSum(int);
private:
int size;
int capacity;
int* ptr;
};
orderedVector::orderedVector(int c) {
capacity = c;
size = 0;
ptr = new int[c];
}
orderedVector::~orderedVector() {
delete[] ptr;
}
int orderedVector::getSize() const {
return size;
}
int orderedVector::getCapacity() const {
return capacity;
}
void orderedVector::doubleCapacity() {
int newCapacity = capacity * 2;
orderedVector temp(capacity);
for (int i = 0; i < size; i++) {
temp.ptr[i] = ptr[i];
}
ptr = new int[newCapacity];
for (int i = 0; i < size; i++) {
ptr[i] = temp.ptr[i];
}
capacity = newCapacity;
}
bool orderedVector::find(int number) const {
for (int i = 0; i <= size; i++)
if (number == ptr[i])
return true;
return false;
}
void orderedVector::insert(int number){
if (find(number)) {
return;
}
if (size == capacity)
doubleCapacity();
if (size == 0)
ptr[0] = number;
else {
int checkpoint = size;
for (int i = 0; i < size; i++) {
if (number < ptr[i]) {
checkpoint = i;
break;
}
}
for (int i = size-1; i >= checkpoint; i--) {
ptr[i + 1] = ptr[i];
}
ptr[checkpoint] = number;
}
size++;
}
void orderedVector::remove(int number) {
if (find(number) == false)
cout << "Number does not exist in the vector.\n";
else {
int checkpoint = 0;
for (int i = 0; i <= size; i++)
if (ptr[i] == number)
checkpoint = i;
for (int i = checkpoint; i < size; i++)
ptr[i] = ptr[i + 1];
}
ptr[size] = 0;
size--;
}
void orderedVector::findSum(int number) {
for (int i = 0; i <= size; i++) {
for (int j = i+1; j <= size; j++) {
if (ptr[i] + ptr[j] == number) {
cout << "The two numbers that have a sum of " << number
<< " are " << ptr[i] << " and " << ptr[j] << endl;
return;
}
}
}
cout << "No two numbers found that give a sum of " << number << endl;
}
ostream& operator<<(ostream& output, const orderedVector& vector) {
for (int i = 0; i < vector.size; i++)
output << vector.ptr[i] << " ";
output << endl;
return output;
}
istream& operator>>(istream& input, orderedVector& vector) {
int x = 0;
for (int i = 0; i < vector.capacity; i++) {
input >> x;
vector.insert(x);
}
return input;
}
似乎当我初始化一个元素,并且数组被完全填充时,我得到这个错误: 检测到堆损坏,CRT 检测到应用程序在堆缓冲区结束后写入内存。
我知道它是析构函数,因为当我删除它时,没有发生任何错误。 另外,当我的向量元素没有完全填满时(容量大于大小),也不会出现错误。 我想知道如何解决这个问题,或者删除运算符的一般工作方式,以及为什么在我填充动态创建的数组时会导致错误。
动态分配最多只能释放一次。因此,当您在析构函数中解除分配时,建立一个 class 不变性很重要,该不变性至多一个实例唯一拥有相同的指针。如果违反了这种不变量,那么这些实例的析构函数可能会尝试 delete
相同的指针两次,这会导致未定义的行为。哪个不好。
您的 class orderedVector
确实在其析构函数中解除了分配。但是,class 的(隐式生成的)复制构造函数复制成员变量,这违反了唯一所有权的 class 不变量。
您未能提供 MCVE,但有理由猜测您的程序复制了 orderedVector
的实例,导致由于多个 delete
而导致未定义的行为相同的指针。
解决方案是使 class 不可复制和不可移动,或者遵循 3(或 5)规则,即以某种方式实现复制(和移动)构造函数和赋值运算符强制执行唯一所有权的不变性。