动态分配数组的析构函数导致堆缓冲区错误

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)规则,即以某种方式实现复制(和移动)构造函数和赋值运算符强制执行唯一所有权的不变性。