[英]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.