【发布时间】:2017-04-19 14:59:58
【问题描述】:
我有一个班级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 类的唯一属性是vector 和map,因此无需声明析构函数、复制赋值运算符和复制构造函数,因为内存是在矢量和地图模板“内部”管理的。
2) 我使用 Python 代码中的这些类(我使用 cython 在 C++ 和 Python 之间进行接口),并且我所做的所有操作都是通过树对象执行的。我认为因为我“使用”的分支包含在树对象中(具有良好的内存管理),所以我不需要为分支类声明析构函数、复制构造函数和复制赋值运算符。但是我遇到了一些问题,我认为我有内存泄漏。
如果这可能导致内存泄漏,有人可以确认我吗?如果是在vector<int> 中存放int hierarchy 避免声明析构函数和公司?
编辑
存放在树中的分支是在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
【问题讨论】:
-
vector<Branch *>将正确管理它所拥有的Branch *,但它不会管理这些指针指向的Branches。创建指针指向的Branches 的人负责摆脱它们,而不是向量。您可以改用vector<Branch>来使向量负责分支。 -
使用
vector不会神奇地免除您管理内存的麻烦。如果parent、children中的任何一个指针指向堆上的对象,最后还是需要释放它们。 -
请同时显示您的
Tree/Branch初始化代码。 -
@BenSteffan 我不能把整个初始化,因为它太大了。现在我没有时间研究一个最小的例子。
-
哪个类拥有您拥有所有这些指针的
Branch对象?您的代码如何知道它们的生命周期何时结束?如果Tree拥有它的分支,那么它必须delete它们。