简体   繁体   中英

Quadtree implementation in C++ : Exception Thrown Read Access Violation

I am attempting to implement a quadtree in C++, however I have a read access violation that I have been spending hours trying to figure out. Note that I have put all the member variables in public, just for debugging efforts.

Whenever I attempt to subdivide a quadrant, ie the root quadrant, I get

Exception thrown: read access violation. std::_Vector_alloc > >::_Myend(...) returned 0xDDDDDDE9.

The quadtree consists of a pointer to an array of contiguous Quadrants, as well as points. These pointers are passed onto every quadrant, so they are able to write to it without making copies.

What am I doing wrong + could you suggest improvements?

Here is my Quadtree Class:

  class Quadtree
{
private:

    Boundary rootBoundary;
public:
    std::vector<Ball>* dataPtr = nullptr;
    std::vector<Quadrant>* quadrantPtr = nullptr;
    Quadtree(const Boundary& b);


};

    Quadtree::Quadtree(const Boundary& bo)
    :rootBoundary(bo)
{
    std::vector<Ball>* bPtr = new std::vector<Ball>;
    std::vector<Quadrant>* qPtr = new std::vector<Quadrant>;
    quadrantPtr = qPtr;
    dataPtr = bPtr;


    Quadrant Root(bo, quadrantPtr, dataPtr);

}

The quadtree houses all of the quadrants, as well as the data storage.

Here is the Quadrant class:

 class Quadrant
    {
    private:

    public:
        std::vector<Quadrant>* quadrantPtr = nullptr;
        std::vector<Ball>* dataPtr = nullptr;
        Boundary m_boundary;
        std::vector<unsigned int> elementIndex;
        int first_child_index = -1;
        int count = 0;

        Quadrant(Boundary b, std::vector<Quadrant>* qPtr, std::vector<Ball>* dPtr);
        void Subdivide();
        bool Insert(Ball* Ball);
        void Display(sf::RenderWindow& myWindow);

    };


Quadrant::Quadrant(Boundary b, std::vector<Quadrant>* qPtr, std::vector<Ball>* bPtr)
    :dataPtr(bPtr), quadrantPtr(qPtr), m_boundary(b)
{
    qPtr->push_back(*this);
}
void Quadrant::Subdivide()
{
    float cx = m_boundary.m_Centre.x;
    float cy = m_boundary.m_Centre.y;
    float qw = m_boundary.m_halfSize.x / 2;
    float qh = m_boundary.m_halfSize.y / 2;

    sf::Vector2f halfSize{ qw, qh };
    first_child_index = quadrantPtr->size();

    Boundary NE(sf::Vector2f{ cx + qw, cy - qh }, halfSize);
    Quadrant NEQ(NE, quadrantPtr, dataPtr);
    Boundary NW(sf::Vector2f{ cx - qw, cy - qh }, halfSize);
    Quadrant NWQ(NW, quadrantPtr, dataPtr);
    Boundary SE(sf::Vector2f{ cx + qw, cy + qh }, halfSize);
    Quadrant SEQ(SE, quadrantPtr, dataPtr);
    Boundary SW(sf::Vector2f{ cx - qw, cy + qh }, halfSize);
    Quadrant SWQ(SW, quadrantPtr, dataPtr);


}

bool Quadrant::Insert(Ball* ball)
{
    if (!m_boundary.ContainsPoint(*ball))
    {
        return false;
    }
    if (count < 4)
    {
        elementIndex.push_back(dataPtr->size());
        count++;
        return true;
    }
    else
    {
        if (first_child_index == -1)
        {
            std::cout << "subdividing" << std::endl;
            Subdivide();
        }
        for (int i = 0; i < 4; i++)
        {
            if (quadrantPtr->at(first_child_index + i).Insert(ball))
            {
                return true;
            }
        }
    }

}

void Quadrant::Display(sf::RenderWindow& myWindow)
{
    myWindow.draw(m_boundary.boundary);
    if (first_child_index != -1)
    {
        for (int i = 0; i < 4; i++)
        {
            quadrantPtr->at(first_child_index + i).Display(myWindow);
        }
    }
}

Here is the boundary class which represents the AABB for the quadrant:

class Boundary
{
private:

public:
    sf::Vector2f m_Centre;
    sf::Vector2f m_halfSize;
    sf::RectangleShape boundary;
    Boundary();
    Boundary(const sf::Vector2f& centre, const sf::Vector2f& halfSize);
    bool ContainsPoint(const Ball& ball) const;
    ~Boundary();

};

Boundary::Boundary()
{

}
Boundary::Boundary(const sf::Vector2f& Centre, const sf::Vector2f& HalfSize)
    :m_Centre(Centre), m_halfSize(HalfSize)
{
    boundary.setSize(m_halfSize + m_halfSize);
    boundary.setOrigin(m_halfSize);
    boundary.setPosition(m_Centre);
    boundary.setFillColor(sf::Color::Transparent);
    boundary.setOutlineColor(sf::Color::White);
    boundary.setOutlineThickness(2);
}
bool Boundary::ContainsPoint(const Ball& ball) const
{
    bool contains = false;
    if (ball.ball.position.x > m_Centre.x - m_halfSize.x && ball.ball.position.x < m_Centre.x + m_halfSize.x)
    {
        if (ball.ball.position.y > m_Centre.y - m_halfSize.y && ball.ball.position.y < m_Centre.y + m_halfSize.y)
        {
            contains = true;
        }
    }
    return contains;
}

Your Root is local to the constructor. That is, it is destroyed right at the end of Quadtree construction. Make it a class member instead.

Also you don't need to create vectors with new , they are basically pointers themselves. Make them class members too, and use & to take address to pass into Quadrant (or pass a reference).

NB Member order is important, it is the order in which they are initialized.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM