内存管理2"互联" C ++类

时间:2017-04-19 14:59:59

标签: c++ class

我有一个班级Branch和一个班级Tree。类的声明如下:

class Branch{

private:

  map<string, double> properties;

  vector<Branch *> parent;
  vector<Branch *> children;

  int hierarchy;

  public: 
  ...

}

class Tree{

private:

  /* Tree is a vector of pointers to branches. */
  vector<Branch*> tree_branches;

  map<int,int> Hierarchy_distribution;

public:
...

}

1)如果我理解得很清楚,Tree类的唯一属性是vectormap,则无需声明析构函数,副本分配运算符和复制构造函数,因为内存管理&#34;内部&#34;矢量和地图模板。

2)我使用python代码中的这些类(我使用cython在C ++和python之间进行接口),我所做的所有操作都是通过树对象执行的。我认为这是因为分支机构I&#34;使用&#34;包含在树对象中(具有良好的内存管理)我不需要为分支类声明析构函数,复制构造函数和复制赋值运算符。但是,我遇到了一些问题,我认为我有内存泄漏。

有人可以确认我是否会导致内存泄漏吗?如果它会将int hierarchy放在vector<int>内,避免声明析构函数和公司?

修改

树中存储的分支是在Tree类的方法内创建的。它看起来像:

Tree::addBranch(){
  Branch* branch2insert=new Branch();
  tree_branches.push_back(branch2insert);
}

作为局部变量,在范围的末尾被branch2insert破坏?我需要写delete branch2insert;吗?有人知道我指向的Branch对象在哪里生活吗?

我仍然不知道为什么我需要确保内存管理,除非在Tree类方法中,我从不分配资源......

这整件事情在我脑海里变得非常凌乱

编辑2:示例

branch.h

#ifndef BRANCH_H_
#define BRANCH_H_

#include <memory>
#include <string>
#include <vector>
#include <map>
using namespace std;

class Branch{

private:

      vector<Branch*> parent;
      vector<Branch*> children;

public:

      Branch();

      bool hasParent();
      bool hasParent(Branch* test);
      void addParent(Branch* p);
      void removeParent();
      Branch* getParent();

      bool hasChildren();
      bool hasChild(Branch*test);
      void addChild(Branch*ch);
      void removeChild(Branch*ch);
      void removeChildren();
      void removeDescendants();
      vector<Branch*> getBrothers();


};

#endif

tree.h中

#ifndef TREE_H_
#define TREE_H_

#include <vector>
#include <map>
#include"branch.h"

using namespace std;

class Tree{

private:

      vector<Branch*> tree_branches;

public:

      Tree();

      int getNumberOfBranches();

      Branch* getBranch(int branch_index); /* Returns branch at index. */
      int getIndex(Branch* branch); /* Returns the index of branch. */

      int getLastDescendantIndex(int ancestor_index); /* Returns index of the last descendant of branch at ancestor index. */
      int getParentIndex(int child_index); /* Returns index of the parent of branch at child_index. */
      vector<int> getBrothersIndex(int branch_index); /* Returns indexes of the brothers of branch at branch_index. */

      void addBranch(int parent_index); /* Adds branch without initializing its properties. */
      void removeBranch(int branch_index); /* Removes branch at branch_index and all its descendants. */

};

#endif

branch.cpp

#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <sstream>
#include <map>
#include <stdio.h>

using namespace std;

#include "branch.h"

Branch::Branch():parent(vector<Branch*>()),children(vector<Branch*>())
        {
        }

bool Branch::hasParent(){
  if(parent.size()==0)
        return false;
    else
    return true;
}

bool Branch::hasParent(Branch* test){
  bool ret = false;
  for(vector<Branch*>::iterator it=parent.begin();it!=parent.end();it++){//traversing parent vector
    if((*it)==test){//if test belong to parent vector
      ret = true;
      break;
    }
  }
  return ret;
}

void Branch::addParent(Branch* mom){
  if(parent.size()==0){//if a branch hasn't a parent, multiple parents aren't allowed in a tree-network
    if(hasParent(mom)==false){//double checking if mom isn't already a parent
            parent.push_back(mom);//adding mom to parent vector
      }
    else{
      cout << "Branch::addParent Error: trying to add a parent twice.\n";
    }
  }
  else{
    cout << "Branch::addParent Error: trying to add a parent to a branch that already has one.\n";
  }
}

void Branch::removeParent(){
    if(this->hasParent()==true){//if this branch has a parent
      vector<Branch*>::iterator it=parent.begin();
      parent.erase(it);//erase it (it is the first and only element of the vector)

    }
    else{
      cout << "Removing the trunk.\n";
    }
}

Branch* Branch::getParent(){
  return parent[0];
}

bool Branch::hasChildren(){
  if(children.size()==0)
        return false;
    else
    return true;
}

bool Branch::hasChild(Branch* test){
  bool ret = false;
  for(vector<Branch*>::iterator it=children.begin();it!=children.end();it++){
    if((*it)==test){
      ret = true;
      break;
    }
  }
  return ret;
}

void Branch::addChild(Branch* ch){
  if(hasChild(ch)==false){
        children.push_back(ch);
        ch->addParent(this); // PARENTHOOD LINK ESTABLISHED IN ADD CHILD. ONLY
                         // NEEDED ONCE.
    }
  else{
        cout << "Branch::addChild Error: trying to add a child but the child has been already added.\n";
  }
}

void Branch::removeChild(Branch* ch){
  if(hasChild(ch)==true){
        for(vector<Branch*>::iterator it=children.begin();it!=children.end();it++){
            if((*it)==ch){
                children.erase(it);
                break;
            }
        }
    }
  else{
      cout << "Branch::removeChild Error: trying to remove a child that doesn't exist.\n";
  }
}

void Branch::removeChildren(){
  if(this->hasChildren()==true){
    children.erase(children.begin(),children.end());
  }
  else{
    cout << "Branch::removeChildren Error: trying to remove all the children of a branch but tha branch hasn't any.\n";
  }
}

void Branch::removeDescendants(){
    if (this!=NULL){
      if(this->hasChildren()==true){
        for(vector<Branch*>::iterator it=children.begin();it!=children.end();it++){
          (*it)->removeDescendants();
        }
      removeChildren();
      }
      for(vector<Branch*>::iterator it=children.begin();it!=children.end();it++){
        (*it)->removeParent();
      }
    }
}

vector<Branch*> Branch::getBrothers(){
  vector<Branch*> brothers;
  vector<Branch*> potential_brothers;
  if (parent.size()!=0){
    potential_brothers=parent[0]->children;
    for (vector<Branch*>::iterator it=potential_brothers.begin();it!=potential_brothers.end();it++){
      if ((*it)!=this){
        brothers.push_back((*it));
      }
    }
  }
  return brothers;
}

tree.cpp

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

#include "tree.h"
Tree::Tree():tree_branches(vector<Branch*>()){
    Branch* trunk=new Branch();
    tree_branches.push_back(trunk);
}

int Tree::getNumberOfBranches(){
    int number_of_branches=tree_branches.size(); //retrieving size of vector
    return number_of_branches;
}

Branch* Tree::getBranch(int index){

      unsigned int u_index=index;
      return tree_branches.at(u_index); // returning branch at index of the tree vector

}


int Tree::getIndex(Branch* branch){
    int index=0;
    for(vector<Branch*>::iterator it=tree_branches.begin();it!=tree_branches.end();it++){
      if((*it)==branch){
        return index;
      }
      index++;
    }
    cout << "Tree::getIndex Error: trying to get the index of a branch we can't find. Returning 0.\n";
    return 0;
}


int Tree::getLastDescendantIndex(int ancestor_index){

      if(tree_branches.at(ancestor_index)->hasChildren()==false){// if it is a leaf
        return ancestor_index;
      }

      if(ancestor_index==0){// if it is the trunk
        int N=tree_branches.size();
        int last_descendant_index=N-1;
        return last_descendant_index;
      }

      vector<int> brothers_indexes=Tree::getBrothersIndex(ancestor_index);

      for(vector<int>::iterator it=brothers_indexes.begin();it!=brothers_indexes.end();it++){

        int brother_index=(*it);
        if(brother_index>ancestor_index){

          int last_descendant_index=brother_index-1;
          cout << "The last descendant of" << ancestor_index << " is "<<last_descendant_index<<"\n";
          return last_descendant_index;

        }
      }
      int parent_index=Tree::getParentIndex(ancestor_index);
      Tree::getLastDescendantIndex(parent_index);
}

int Tree::getParentIndex(int child_index){

      if(child_index==0){ //if considered branch is the trunk
        cout << "Tree::getParentIndex: the trunk hasn't a parent. Returning -1.\n";
        return -1;
      }

      unsigned int u_child_index=child_index;
      Branch* parent=tree_branches.at(u_child_index)->getParent(); //retrieving the parent of the considered branch
      int parent_index=Tree::getIndex(parent);
      return parent_index; //returning parent index
}


vector<int> Tree::getBrothersIndex(int branch_index){
    vector<int> brothers_index;

    Branch* this_branch=Tree::getBranch(branch_index);//retrieving the branch from the index
    vector<Branch*> brothers=this_branch->getBrothers();//retrieving branch's brothers

    for(vector<Branch*>::iterator it=brothers.begin();it!=brothers.end();it++){ //traversing a vector containing the brothers of the consideered branch
      int this_index=Tree::getIndex(*it); //retrieving index of a brother
      brothers_index.push_back(this_index); //stocking the index in a vector
    }

    return brothers_index; //returning the vector containing the index of all brothers
  }


void Tree::addBranch(int parent_index){

      unsigned int u_parent_index=parent_index;
      Branch* mom=tree_branches.at(u_parent_index);//getting futur parent
      Branch* branch2insert=new Branch();//creation of branch to insert
      mom->addChild(branch2insert);//setting family relationship

      vector<Branch*>::iterator begin=tree_branches.begin();//creating iterators to manipulate vector elements
      unsigned int inserting_position=u_parent_index+1;//initializing inserting_position
      tree_branches.insert(begin+inserting_position,branch2insert);//inserting new branch

}


void Tree::removeBranch(int branch_index){

      int N=tree_branches.size();

      unsigned int u_branch_index=branch_index;
      Branch* branch2remove=tree_branches.at(u_branch_index);
      branch2remove->removeParent(); //removing parenthood link, if branch2remove is the trunk nothing will be done

      if(branch_index!=0){//removing childhood link between parent and branch_index
        Branch* branch2removeParent=branch2remove->getParent();
        branch2removeParent->removeChild(branch2remove);
      }

      int last_descendant_index=Tree::getLastDescendantIndex(branch_index);
      cout<<"The branch to remove is "<<branch_index<<", its last descendant index is "<<last_descendant_index<<", the size of the tree is "<<N<<".\n";

      branch2remove->removeDescendants();//removing family links for all descendents

      if(last_descendant_index==N-1){
        vector<Branch*>::iterator begin=tree_branches.begin();
        tree_branches.erase(tree_branches.begin()+u_branch_index,tree_branches.end());
      }

      else{
        vector<Branch*>::iterator begin=tree_branches.begin();
        unsigned int u_last_descendant_index=last_descendant_index;
        tree_branches.erase(tree_branches.begin()+u_branch_index,tree_branches.begin()+u_last_descendant_index+1);//removing the considered branch and its descendents from the tree vector
      }
}

TEST.CPP

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <typeinfo>
#include <vector>
#include <map>
#include <string>
#include "tree.h"



using namespace std;

int main(){

  Tree tree;
  tree=Tree();

  for(int i=0;i<5;i++){
    int N=tree.getNumberOfBranches();
    for(int j=0;j<N;j++){
      tree.addBranch(j);
      tree.addBranch(j);
    }
  }

  tree.removeBranch(21);
  tree.removeBranch(30);
  tree.removeBranch(50);

  return 0;
}

编译:

g ++ -Wall -pedantic -c

2 个答案:

答案 0 :(得分:3)

  

1)如果我理解得很好,Tree类的唯一属性是向量和映射,则不需要声明析构函数,复制 - 分配运算符和复制构造函数,因为内存是受管理的#34;内部&#34;矢量和地图模板。

这里你错了,因为在向量内部管理的内存只是分支地址的存储Branch *)。当您插入某个分支时,您会调用类似tree_branches.push_back(new Branch)的内容,不要?因此,您需要以某种方式调用相应的delete,否则树的默认析构函数不会负责调用Branch es的析构函数。

对代码的快速修复可能会从Branch *切换到shared_ptr<Branch>。这样,当tree_branches向量被销毁时,shared_ptr也将被销毁,当最新的shared_ptr到任何Branch被销毁时,指向的Branch将是。

  

将int层次结构存储在向量中,避免声明析构函数和公司吗?

它会改变插孔深蹲,因为Branch默认析构函数仍然不会被调用,因此永远不会调用Branch es成员的析构函数。

答案 1 :(得分:0)

最终没有内存泄漏。感谢@Yunnosch提到Valgrind,我不知道这种工具存在。

@Davide我接受了你的答案,因为它为我所做的提供了一个替代方案,即使我的代码中的内存管理显然没有问题。

我发布的代码在函数Tree :: getLastDescendantIndex中存在问题。