我在这个C++赋值中使用unique_ptr和shared_ptr,代码运行良好,直到最后显示
free(): invalid pointer
Aborted (core dumped)
我不知道这是怎么发生的。
该代码解析文件"resource.txt"并构建一个图。每个单词都是一个节点,每一行都意味着两个单词之间的依赖关系。resource.txt
handgun bullets
bullets ore
bombs ore
turret bullets
以下是我的输出和代码:
的输出/主
adding edge: 'handgun' --> 'bullets'
adding edge: 'bullets' --> 'ore'
adding edge: 'bombs' --> 'ore'
adding edge: 'turret' --> 'bullets'
graph now has nodes:
bombs-->
ore
ore-->
turret-->
bullets
handgun-->
bullets
bullets-->
ore
=======
graph destructor
destructor of node: bombs
destructor of node: turret
destructor of node: handgun
destructor of node: bullets
destructor of node: turret
free(): invalid pointer
Aborted (core dumped)
你可以看到,每个析构函数都被调用了,我正在使用智能指针,但我仍然得到了无效的指针错误。
main.cpp
#include "graph.h"
#include <memory>
int main(int argc, char const *argv[])
{
unique_ptr<graph> g(new graph("./resource.txt"));
g->dispay();
cout << "=======" << endl;
return 0;
}
图形.h
#ifndef Tan_Li_Graph_Head_
#define Tan_Li_Graph_Head_
#include "node.h"
#include <unordered_map>
#include <memory>
#include <iostream>
#include <string>
using namespace std;
class graph
{
private:
/* data */
public:
unordered_map<string, shared_ptr<node>> nodes;
graph(string resourceFileName);
bool addEdge(string from, string to);
void delNode(string name);
void dispay();
~graph();
};
#endif
graph.cpp
#include "graph.h"
#include <fstream>
#include <utility>
using namespace std;
graph::graph(string fileName)
{
ifstream file(fileName);
string str;
while (getline(file, str))
{
if (str.back() == 'r')
{
str.pop_back();
}
auto space_loc = str.find(" ");
string from = str.substr(0, space_loc);
string to = str.substr(space_loc + 1);
this->addEdge(from, to);
}
}
bool graph::addEdge(string from, string to)
{
cout << "adding edge: '" << from << "' --> '" << to << "'" << endl;
if (this->nodes.count(from) == 0)
{
shared_ptr<node> node_from = make_shared<node>(from);
this->nodes.insert(make_pair(from, node_from));
}
if (this->nodes.count(to) == 0)
{
shared_ptr<node> node_to = make_shared<node>(to);
this->nodes.insert(make_pair(to, node_to));
}
return this->nodes[from]->addChild(this->nodes[to]);
}
void graph::delNode(string name)
{
auto node_to_del = this->nodes[name];
for (auto parent : node_to_del->parents)
{
parent.second->delChild(node_to_del);
}
for (auto child : node_to_del->children)
{
node_to_del->delChild(child.second);
}
}
void graph::dispay()
{
cout << "graph now has nodes: " << endl;
for (auto node_to_display : this->nodes)
{
// cout << node_to_display.second->name << ": " << (node_to_display.second->useable ? "usable" : "NOT usable")
// << " ;" << endl;
cout << node_to_display.second->name << "-->" << endl;
for (auto child : node_to_display.second->children)
{
cout << 't' << child.second->name << endl;
}
}
}
graph::~graph()
{
cout << "graph destructor" << endl;
}
node.h
#ifndef Tan_Li_Node_Head_
#define Tan_Li_Node_Head_
#include <string>
#include <unordered_map>
#include <memory>
#include <iostream>
using namespace std;
class node
{
private:
/* data */
public:
string name;
bool useable;
unordered_map<string, shared_ptr<node>> children;
unordered_map<string, shared_ptr<node>> parents;
node(string name);
bool addChild(shared_ptr<node> child);
bool addChild(string name);
bool delChild(shared_ptr<node> child);
bool delChild(string name);
~node();
};
#endif
node.cpp
#include "node.h"
#include <utility>
using namespace std;
node::node(string name)
{
this->name = name;
this->useable = true;
}
bool node::addChild(shared_ptr<node> child)
{
string child_name = child->name;
if (child_name.compare(this->name) == 0)
{
cout << "Node " << this->name << " can't add itself to children" << endl;
return false;
}
if (this->children.count(child_name) == 0)
{
this->children.insert(make_pair(child_name, child));
child->parents.insert(make_pair(this->name, this));
}
else
{
cout << "Node " << child_name << " is already in the child of node " << this->name << endl;
return false;
}
return true;
}
bool node::addChild(string name)
{
if (name.compare(this->name) == 0)
{
cout << "Node " << this->name << " can't add itself to children" << endl;
return false;
}
shared_ptr<node> child = make_shared<node>(name);
this->addChild(child);
}
bool node::delChild(shared_ptr<node> child)
{
string child_name = child->name;
if (this->children.count(child_name) == 0)
{
cout << "Node " << child_name << " is NOT the child of node " << this->name << endl;
return false;
}
else
{
child->parents.erase(this->name);
this->children.erase(child_name);
}
this->useable = false;
return true;
}
bool node::delChild(string name)
{
if (this->children.count(name) == 0)
{
cout << "Node " << name << " is NOT the child of node " << this->name << endl;
return false;
}
else
{
this->children[name]->parents.erase(this->name);
this->children.erase(name);
}
this->useable = false;
return true;
}
node::~node()
{
cout << "destructor of node: " << this->name << endl;
}
问题很可能是这一行:
child->parents.insert(make_pair(this->name, this));
您正在做的是从this
指针隐式创建一个shared_ptr
。
请参阅此以获得对您的问题的较小的重新处理。
shared_ptr
是牢不可破的誓言。一旦指针由shared_ptr
管理,其生命周期就可能不受任何其他类/包装器的控制。this
指针的内存已经创建,因此由shared_ptr
的另一个实例管理。通过使用this
(隐式)创建shared_ptr
的另一个实例,您违反了约定。
有几种方法可以解决这个问题。一种方法是保留任何后边缘的原始指针(例如父对象的原始指针)。通过这种方式,父对象控制子对象的循环。另一种方法是使用
unordered_map<string, weak_ptr<node>> parents;
您必须从enable_shared_from_this派生node
,然后执行:
child->parents.insert(make_pair(this->name, weak_from_this()));
此的弱点
请注意,您可以对父级和子级都使用shared_ptr
,但这将是循环引用,并且会泄漏内存。