我有以下代码用于在图形内创建节点。当我运行静态检查工具(覆盖率)时,我遇到了资源泄漏错误。如果您能指出如何改进代码,我将不胜感激:
class node {
public :
explicit node(std::string& name) : m_name(name) { }
void setlevel(int level)
{ m_level = level; }
private :
...
}
class graph {
public :
void populateGraph()
{
std::string nodeName = getNodeName();
/* I get error saying variable from new not freed or pointed-to in function
nc::node::node(const std::string...) */
node* NodePtr = new node(nodeName);
/* I get error saying variable NodePtr not freed or pointed-to in function
nc::node::setLevel(int) */
NodePtr->setLevel(-1);
if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end())
m_name2NodeMap[nodeName] = NodePtr;
NodePtr = NULL;
}
....
private :
std::map< std::string, node*> m_name2NodeMap;
}
我认为我需要在delete NodePtr
中populateGraph
,但随后发布它将调用节点析构函数(~node
)并从图中删除该节点。所以,我设置NodePtr=NULL
以查看它是否有用,但事实并非如此。
答案 0 :(得分:3)
我不熟悉覆盖率或它使用的确切规则,但如果节点的名称已经在地图中,您似乎会有内存泄漏。也就是说,如果你的if语句的主体没有被执行,那么你就会松开指向你刚刚分配的内存的指针。也许你想要这样的东西:
if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end())
m_name2NodeMap[nodeName] = NodePtr;
else
delete NodePtr;
NodePtr = NULL;
编辑:由于我几乎与Daemin同时回复,让我添加更多细节:
正如ildjarn所提到的,你还需要通过添加析构函数来解除分配在地图中最终的对象:
~graph()
{
for( std::map< std::string, node*>::iterator i = m_name2NodeMap.begin();
i != m_name2NodeMap.end(); ++i )
{
delete i->second;
}
}
为了完整起见,我应该注意:
处理复杂对象生命周期的首选方法是使用智能指针。例如,boost::shared_ptr或tr1 :: shared_ptr就像这样工作。注意:我的语法可能不完整。
class node {
...
}
class graph {
public :
void populateGraph()
{
std::string nodeName = getNodeName();
boost::shared_ptr< node > NodePtr( new node(nodeName) );
NodePtr->setLevel(-1);
if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end())
m_name2NodeMap[nodeName] = NodePtr;
}
....
private :
std::map< std::string, boost::shared_ptr<node> > m_name2NodeMap;
}
};
看看我们如何消除析构函数和显式删除调用?现在节点对象将像节点名一样自动销毁。
在另一个节点上,您应该查看std::map::insert函数,该函数应该将if语句全部消除。
答案 1 :(得分:2)
您需要做的是为graph
提供一个析构函数,并delete
node*
m_name2NodeMap
中的所有else
。当然,因为你需要一个析构函数,你还需要一个复制构造函数和一个复制赋值运算符,否则你肯定会得到内存损坏。
您还需要if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end())
到delete NodePtr;
的{{1}}条款。
答案 2 :(得分:1)
如果不将NodePtr
添加到列表中,则不会释放if
。 delete NodePtr;
语句需要您if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end())
{
m_name2NodeMap[nodeName] = NodePtr;
}
else
{
delete NodePtr;
}
NodePtr = NULL;
{{1}}
答案 3 :(得分:1)
其他人已经涵盖了泄漏的问题。实际上有很多泄漏,所以我甚至都不会对它们进行评论...(populateGraph
,~Graph
,Graph(Graph const&)
和Graph& operator=(Graph const&)
至少。 ..)
我更愿意提供一个有效的简单解决方案:
class Graph
{
public:
void addNode(std::string name) {
_nodes.insert(std::make_pair(name, Node(name));
}
private:
std::map<std::string, Node> _nodes;
};
这里发生了什么?
map
可以完美地包含值Node
,并且您不会以这种方式泄漏。std::map::insert
只会在没有等效密钥的情况下执行插入操作,无需执行find
+ []
(这是因为您计算两倍的地方而复杂的两倍存储元素)