简体   繁体   English

在 C++ 中实现 A* 时可能出现内存泄漏

[英]Possible memory leak when implementing A* in C++

I have been programming for a little while, but I am relativly new to c++.我已经编程了一段时间,但我对 C++ 比较陌生。 I am trying to implement the A* algorithm and have managed to produce the code below.我正在尝试实现 A* 算法并设法生成下面的代码。 The implementation producces the expected result, the shortest path from point A to B in a 2D grid, but I suspect i leave behind some memory leaks.该实现产生了预期的结果,即二维网格中从 A 点到 B 点的最短路径,但我怀疑我留下了一些内存泄漏。

I tested this by overloading the new and delete operators to keep track of the amount of bytes allocated on the heap and it showed that a lot of memeory never got released.我通过重载 new 和 delete 运算符来跟踪在堆上分配的字节量来测试这一点,它表明很多内存从未被释放。 However I also tested the number of nodes that never got deleted but it showed that there were that all allocated nodes also got their destructor called.然而,我还测试了从未被删除的节点数量,但它表明所有分配的节点也调用了它们的析构函数。 Note in the code that i only call new on Node, hence my confunsion.请注意,在代码中我只在 Node 上调用 new,因此我感到困惑。 I have much confusion about this and would be happy for an explenation.我对此有很多困惑,很高兴能得到解释。

I have tried using smart pointers, but enden up with circular refrences which were difficult to resolve.我曾尝试使用智能指针,但最终得到了难以解决的循环引用。

This is also my first post on Stack Overflow so please feel free to point how I can improve my questions.这也是我在 Stack Overflow 上的第一篇文章,所以请随时指出我如何改进我的问题。 Thanks in advance.提前致谢。

#include<vector>
#include<array>
#include<cmath>

int mynodes = 0;
int memory_left = 0;

void* operator new(size_t size)
{
    memory_left += size;
    return malloc(size);
}

void operator delete(void* memory, size_t size)
{
    memory_left -= size;
    free(memory);
}

struct Node{
    std::array<int, 2> position;
    Node* parent = nullptr;
    double h, g, f;

    Node(const std::array<int, 2>& pos)
        :position(pos){mynodes++;}


    ~Node(){ mynodes--; }
};


std::vector<std::array<int, 2>> find_children(const std::vector<std::vector<int>>& grid, const std::array<int, 2>& pos){

    std::vector<std::array<int, 2>> children;
    children.reserve(8);

    for(int t = -1; t < 2; t++){
        for(int q = -1; q < 2; q++){
            if(t != 0 || q != 0){
                if(abs(t) == abs(q)) continue;

                std::array<int, 2> cur_pos = {pos[0]+q, pos[1]+t};
                if(cur_pos[0] >= 0 && cur_pos[0] < grid[0].size() && cur_pos[1] >= 0 && cur_pos[1] < grid.size())
                {
                    if(grid[cur_pos[1]][cur_pos[0]] == 0)
                    {
                        children.push_back(cur_pos);
                    }
                }
            }
        }
    }

    return children;
}

bool search_vect(const std::vector<Node*>& set, const std::array<int, 2>& pos)
{
    for(Node* node : set)
    {
        if(node->position[0] == pos[0] && node->position[1] == pos[1]) return true;
    }
    return false;
}

void releaseNodes(std::vector<Node*>& set)
{
    for(auto& node : set)
    {
        delete node;
    }
    set.clear();
}

std::vector<std::array<int, 2>> find_path(const std::vector<std::vector<int>>& grid, std::array<int, 2> start, std::array<int, 2> end){

    Node* cur_node = new Node(start);
    std::vector<Node*> open_vect;
    std::vector<Node*> closed_vect;
    open_vect.push_back(cur_node);

    while(cur_node->position != end){

        double lowest_f = INFINITY;
        size_t idx = 0;
        for(size_t i = 0; i < open_vect.size(); i++)
        {
            if(open_vect[i]->f < lowest_f)
            {
                cur_node = open_vect[i];
                lowest_f = cur_node->f;
                idx = i;
            }
        }
        open_vect.erase(open_vect.begin() + idx);

        std::vector<std::array<int, 2>> children = find_children(grid, cur_node->position);
        closed_vect.push_back(cur_node);

        for(const auto& child_pos : children){
            // if(closed_vect.find(child_pos) != closed_vect.end() || open_vect.find(child_pos) != open_vect.end()) continue;
            if(search_vect(closed_vect, child_pos) || search_vect(open_vect, child_pos))
            {
                continue;
            }

            Node* new_node = new Node(child_pos);
            new_node->g = cur_node->g + 1;
            new_node->h = abs(end[0] - child_pos[0]) + abs(end[1] - child_pos[1]);
            new_node->f = new_node->g + new_node->h;
            new_node->parent = cur_node;

            // double h = sqrt(pow(end[0] - child_pos[0], 2) + pow(end[1] - child_pos[1], 2));

            open_vect.push_back(new_node);

        }
    }

    std::vector<std::array<int, 2>> path;
    while(cur_node != nullptr){
        path.push_back(cur_node->position);
        cur_node = cur_node->parent;
    }

    releaseNodes(open_vect);
    releaseNodes(closed_vect);

    return path;
}


int main()
{
    std::vector<std::vector<int>> grid( 100 , std::vector<int> (100, 0));

    {
        auto path = find_path(grid, {1, 1}, {98, 98});
    }


}

Here the minimal/easy way of getting rid of any explicit new/delete:这是摆脱任何显式新/删除的最小/简单方法:

#include<vector>
#include<array>
#include<cmath>

struct Node{
    std::array<int, 2> position;
    Node* parent = nullptr;
    double h{0.};
    double g{0.};
    double f{0.};
    Node(const std::array<int, 2>& pos)
        : position(pos) {}
};


std::vector<std::array<int, 2>> find_children(const std::vector<std::vector<int>>& grid, const std::array<int, 2>& pos){

    std::vector<std::array<int, 2>> children;
    children.reserve(8);

    for(int t = -1; t < 2; t++){
        for(int q = -1; q < 2; q++){
            if(t != 0 || q != 0){
                if(abs(t) == abs(q)) continue;

                std::array<int, 2> cur_pos = {pos[0]+q, pos[1]+t};
                if(cur_pos[0] >= 0 && cur_pos[0] < grid[0].size() && cur_pos[1] >= 0 && cur_pos[1] < grid.size())
                {
                    if(grid[cur_pos[1]][cur_pos[0]] == 0)
                    {
                        children.push_back(cur_pos);
                    }
                }
            }
        }
    }

    return children;
}

bool search_vect(const std::vector<Node*>& set, const std::array<int, 2>& pos)
{
    for(Node* node : set)
    {
        if(node->position[0] == pos[0] && node->position[1] == pos[1]) return true;
    }
    return false;
}

std::vector<std::array<int, 2>> find_path(const std::vector<std::vector<int>>& grid, std::array<int, 2> start, std::array<int, 2> end){

    std::vector<Node> nodes{};
    nodes.emplace_back(start);
    Node* cur_node = &nodes.back();
    std::vector<Node*> open_vect;
    std::vector<Node*> closed_vect;
    open_vect.push_back(cur_node);

    while(cur_node->position != end){

        double lowest_f = INFINITY;
        size_t idx = 0;
        for(size_t i = 0; i < open_vect.size(); i++)
        {
            if(open_vect[i]->f < lowest_f)
            {
                cur_node = open_vect[i];
                lowest_f = cur_node->f;
                idx = i;
            }
        }
        open_vect.erase(open_vect.begin() + idx);

        std::vector<std::array<int, 2>> children = find_children(grid, cur_node->position);
        closed_vect.push_back(cur_node);

        for(const auto& child_pos : children){
            // if(closed_vect.find(child_pos) != closed_vect.end() || open_vect.find(child_pos) != open_vect.end()) continue;
            if(search_vect(closed_vect, child_pos) || search_vect(open_vect, child_pos))
            {
                continue;
            }
            nodes.emplace_back(child_pos);
            Node* new_node = &nodes.back();
            new_node->g = cur_node->g + 1;
            new_node->h = abs(end[0] - child_pos[0]) + abs(end[1] - child_pos[1]);
            new_node->f = new_node->g + new_node->h;
            new_node->parent = cur_node;

            // double h = sqrt(pow(end[0] - child_pos[0], 2) + pow(end[1] - child_pos[1], 2));

            open_vect.push_back(new_node);

        }
    }

    std::vector<std::array<int, 2>> path;
    while(cur_node != nullptr){
        path.push_back(cur_node->position);
        cur_node = cur_node->parent;
    }

    return path;
}


int main()
{
    std::vector<std::vector<int>> grid( 100 , std::vector<int> (100, 0));

    {
        auto path = find_path(grid, {1, 1}, {98, 98});
    }


}

This is not perfect, but it easily demonstrates how easy it is to not cause any potential memory leaks.这并不完美,但它很容易证明不引起任何潜在的内存泄漏是多么容易。 Instead of replacing the vectors of pointers with vectors of nodes, I just added an additional vector of nodes (the owner).我没有用节点向量替换指针向量,而是添加了一个额外的节点向量(所有者)。 Now the pointers are non-owning and nothing weird should happen anymore.现在指针是非拥有的,不会再发生任何奇怪的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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