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

时间:2015-11-10 17:34:09

标签: c++ c++11

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

问题是,程序以STATUS_ACCESS_VIOLATION退出,我无法弄清楚为什么......我也尝试使用调试器检测问题,但是在发生错误之前,所有事情似乎都能正常工作。你能帮我吗?

我试图将代码简化为mutch,因为它是可能的&通过评论标记了代码的部分问题。

感谢您的帮助。

#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:\Users\Martin\Documents\Skola\PJC\Problem\dist\Debug\Cygwin-Windows\problem.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

1 个答案:

答案 0 :(得分:1)

在这个构造函数中。如果大小为零,则对象将保持未定义状态。

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

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

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

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

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

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

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

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

因为你已经从正常情况下实现了倒退,所以我无法发现问题。这应该是它的样子:

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);
    }
};