对象创建期间的资源泄漏

时间:2011-04-12 02:00:08

标签: c++ pointers graph coverity-prevent

我有以下代码用于在图形内创建节点。当我运行静态检查工具(覆盖率)时,我遇到了资源泄漏错误。如果您能指出如何改进代码,我将不胜感激:

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 NodePtrpopulateGraph,但随后发布它将调用节点析构函数(~node)并从图中删除该节点。所以,我设置NodePtr=NULL以查看它是否有用,但事实并非如此。

4 个答案:

答案 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;
    }
}

为了完整起见,我应该注意:

  1. 析构函数完成后,地图将自动删除,因为它是一个成员变量。
  2. 删除地图时,节点地图中的条目将自动删除。
  3. 删除条目时将删除字符串键。

  4. 处理复杂对象生命周期的首选方法是使用智能指针。例如,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添加到列表中,则不会释放ifdelete NodePtr;语句需要您if (m_name2NodeMap.find(nodeName) == m_name2NodeMap.end()) { m_name2NodeMap[nodeName] = NodePtr; } else { delete NodePtr; } NodePtr = NULL;

的其他内容
{{1}}

答案 3 :(得分:1)

其他人已经涵盖了泄漏的问题。实际上有很多泄漏,所以我甚至都不会对它们进行评论...(populateGraph~GraphGraph(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 + [](这是因为您计算两倍的地方而复杂的两倍存储元素)