簡體   English   中英

在 C++ 中實現 A* 時可能出現內存泄漏

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

我已經編程了一段時間,但我對 C++ 比較陌生。 我正在嘗試實現 A* 算法並設法生成下面的代碼。 該實現產生了預期的結果,即二維網格中從 A 點到 B 點的最短路徑,但我懷疑我留下了一些內存泄漏。

我通過重載 new 和 delete 運算符來跟蹤在堆上分配的字節量來測試這一點,它表明很多內存從未被釋放。 然而,我還測試了從未被刪除的節點數量,但它表明所有分配的節點也調用了它們的析構函數。 請注意,在代碼中我只在 Node 上調用 new,因此我感到困惑。 我對此有很多困惑,很高興能得到解釋。

我曾嘗試使用智能指針,但最終得到了難以解決的循環引用。

這也是我在 Stack Overflow 上的第一篇文章,所以請隨時指出我如何改進我的問題。 提前致謝。

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


}

這是擺脫任何顯式新/刪除的最小/簡單方法:

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


}

這並不完美,但它很容易證明不引起任何潛在的內存泄漏是多么容易。 我沒有用節點向量替換指針向量,而是添加了一個額外的節點向量(所有者)。 現在指針是非擁有的,不會再發生任何奇怪的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM