使用(非指针)引用时的C++STATUS_ACCESS_VIOLATION

C++ STATUS_ACCESS_VIOLATION when using (non-pointer) reference

本文关键字:C++STATUS ACCESS VIOLATION 引用 指针 使用      更新时间:2023-10-16

我是C++的新手,作为我任务的一部分(在主题C++中),我必须实现一些简化的结构,如Array(类似于类向量)和Heap(类似于class priority_queue)&使用它们,如下代码所示。

问题是,程序退出时带有STATUS_ACCESS_VIOLATION,我无法弄清楚为什么。。。我也尝试过使用调试器来检测问题,但在出现错误之前,一切似乎都很正常。你能帮帮我吗?

我试着尽可能多地简化代码&用注释标记代码中有问题的部分。

谢谢你的帮助。

#include <cstdlib>
#include <iostream>
using namespace std;
template<class T>
class Array {
protected:
    T* _data;
    int* inst;
    int _size;
public:
    Array() {
        _data = 0;
        inst = 0;
        _size = 0;
    }
    Array(int size) {
        _data = new T[size];
        inst = new int(1);
        this->_size = size;
    }
    Array(const Array& origin) {
        _data = 0;
        inst = 0;
        _size = 0;
        *this = origin;
    }
    /************* Arithmetic operators *************/
    virtual Array& operator=(const Array& origin) {
        if (inst) {
            this->~Array();
        }
        if (inst = origin.inst) {
            _data = origin._data;
            (*inst)++;
            _size = origin._size;
        }
        return *this;
    }
    /************* Member and pointer operators *************/
    virtual inline T& operator[](const int& index) const {
        return _data[index];
    }
    /************* Destructor *************/
    virtual ~Array() {
        if (inst) {
            if (!--(*inst)) {
                delete[] _data;
                delete inst;
            }
            inst = 0;
            _data = 0;
            _size = 0;
        }
    }
};
template<class T, int Comparator(const T& v1, const T& v2)>
class Heap : public Array<T> {
protected:
    int _length = 0;
public:
    Heap() : Array<T>::Array() {
    }
    Heap(const Heap& origin) : Array<T>::Array((Array<T>) origin) {
        _length = origin._length;
    }
    Heap(int size) : Array<T>::Array(size) {
        _length = 0;
    }
    /************* Arithmetic operators *************/
    virtual Heap& operator=(const Heap& origin) {
        Array<T>::operator=((Array<T>) origin);
        _length = origin._length;
        return *this;
    }
    /************* Heap functions *************/
    virtual inline T top() const {
        return (*this)[0];
    }
    virtual Heap& push(T item) {
        int index, parent;
        for (index = _length++; index; index = parent) {
            parent = (index - 1) >> 1;
            if (Comparator(item, (*this)[parent]) >= 0) {
                break;
            }
            (*this)[index] = (*this)[parent];
        }
        // Identified problem part... but why???
        (*this)[index] = item;
        return *this;
    }
    virtual Heap& pop() {
        int index, swap, other;
        T& temp = (*this)[--_length];
        // Reorder the elements
        for (index = 0; 1; index = swap) {
            // Find the child to swap with
            swap = (index << 1) + 1;
            // If there are no children, the heap is reordered
            if (swap >= _length) {
                break;
            }
            other = swap + 1;
            if ((other < _length) && Comparator((*this)[other], (*this)[swap]) < 0) {
                swap = other;
            }
            // If the bigger child is less than or equal to its parent, the heap is reordered
            if (Comparator(temp, (*this)[swap]) <= 0) {
                break;
            }
            (*this)[index] = (*this)[swap];
        }
        (*this)[index] = temp;
        return *this;
    }
};
struct Edge {
    int from;
    int to;
    double cost;
    Edge() {
    }
    Edge(int from, int to, double cost) : from(from), to(to), cost(cost) {
    }
};
int minEdge(const Edge& e1, const Edge& e2) {
    return e1.cost - e2.cost;
}
typedef Heap<Edge, minEdge> EdgeQueue;
int minQueue(const EdgeQueue& eq1, const EdgeQueue& eq2) {
    return eq1.top().cost - eq2.top().cost;
}
typedef Heap<EdgeQueue, minQueue> EdgeQueueQueue;
int main(int argc, char** argv) {
    Array<EdgeQueue> queues(5);
    for (int i = 0; i < 5; i++) {
        EdgeQueue queue(10);
        for (int j = 0; j < 10; j++) {
            Edge e(i, j, i * j);
            queue.push(e);
        }
        queues[i] = queue;
    }
    EdgeQueueQueue stack(5);
    stack.push(queues[0]);
    stack.pop();
    // So far so good, but this will fail
    stack.push(queues[0]);
    return 0;
}

stackdump文件的内容:

Exception: STATUS_ACCESS_VIOLATION at rip=00000000000
rax=0000000600042348 rbx=000000000024CAF0 rcx=0000000600042348
rdx=000000000024CA60 rsi=0000000600028390 rdi=0000000000000000
r8 =0000000000000000 r9 =0000000180300400 r10=0000000000250000
r11=00000003FE2B365C r12=0000000000000000 r13=0000000000000000
r14=000000000024CB61 r15=0000000000000000
rbp=000000000024C980 rsp=000000000024C948
program=C:UsersMartinDocumentsSkolaPJCProblemdistDebugCygwin-Windowsproblem.exe, pid 2584, thread main
cs=0033 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame        Function    Args
End of stack trace

在此构造函数中。如果大小为零,则对象处于未定义状态。

Array(int size) {
    if (size > 0) {

请记住,POD的初始值是不确定的(即任何东西,从技术上讲都是UB)。

在复制构造函数中使用赋值运算符是唯一的(但有效)

Array(const Array& origin) {
    _data = 0;
    inst = 0;
    _size = 0;
    *this = origin;
}

通常,我们使用复制和交换习惯用法,根据复制构造函数来定义赋值运算符。

您可以手动调用析构函数。

    if (inst) {
        this->~Array();
    }

但您应该调用构造函数来重新初始化对象(这与我将查找的寿命有关)。此外,你也不会检查自我分配。因此,如果你进行自我分配,你会删除对象(删除内容),然后将其分配给自己(留空)。

因为你已经从正常情况下向后实现了一些东西,所以我无法完全发现问题所在。这就是它应该看起来的样子:

template<class T>
class Array {
protected:
    int  size;
    T*   data;
    int* inst;
public:
    virtual ~Array()
    {
        --(*inst);
        if (*inst == 0) {
            delete [] data;
            delete inst;
        }
    }
    Array(std::size_t size = 0)
        : size(size)
        , data(new T[size])        // If this throws no problem.
        , inst(nullptr)
    {
        try {
            inst = new int(1);
        }
        catch(...) {
            delete [] data;  // If we catch the new int(1) failed.
            throw;           // We need to release the data and
        }                    // and allow the exception to propagate.
    }
    Array(Array const& origin)
        : size(origin.size)
        , data(origin.data)
        , inst(origin.inst)
    {
        ++(*inst);
    }
    virtual Array& operator=(Array origin) // Copy and Swap idium
    {
        origin.swap(*this);
    }
    void swap(Array& other) noexcept
    {
        using std::swap;
        swap(size, other.size);
        swap(data, other.data);
        swap(inst, other.inst);
    }
};