我对析构函数有点麻烦。在目前的状态下,它会产生一个段错误。请注意,析构函数只是实现的,并且从不在任何地方显式调用。无论断点位于何处,都会出现段错误。
这是析构函数:
Graph::~Graph() {
while(!children.empty()) {
for(vector<Graph*>::iterator itr = children.begin(); itr != children.end(); ++itr) {
delete *itr;
}
children.clear();
delete parent;
delete tab;
}
}
我也做了这样的变化,没有更好的结果:
Graph::~Graph() {
while(!children.empty()) {
for(unsigned i = 0; i < children.size(); i++)
{
delete children.at(i);
}
children.clear();
delete parent;
delete tab;
}
}
这是类声明:
class Graph
{
private :
Graph* parent;
vector<Graph*> children;
Board* tab;
public :
Graph(Board);
Graph(Board, Graph*);
~Graph();
void AddNode(Board&);
// Graph& BFS(Graph&);
Graph& operator=(Graph source);
vector<Graph*>& getchildren();
Graph* getparent();
Board* gettab();
};
class Board {
private :
int** tab;
int nbline;
int nbcolumn;
Position emptyspot;
public :
Board();
Board(int, int, Play&);
Board(int, int);
Board(const Board&);
Board(int, int, ifstream&);
~Board();
void setValue(Position&, int);
void setNbline(int m);
void setNbcolumn(int n);
int getValue(Position&);
int getNbline();
int getNbcolumn();
int getEmptyline();
int getEmptycolumn();
void setEmptySpot(Position&);
Position& getEmptySpot();
Board& operator=(Board& source);
};
Board::~Board()
{
for(int i = 0; i < this->nbline; i++)
{
delete tab[i];
}
delete tab;
}
我对调试器并不是很舒服且缺乏经验,所以我真的不知道如何正确使用它。此行的调用堆栈点是stl_vector.h:
/**
* Returns a read-only (constant) iterator that points one past
* the last element in the %vector. Iteration is done in
* ordinary element order.
*/
const_iterator
end() const _GLIBCXX_NOEXCEPT
{ return const_iterator(this->_M_impl._M_finish); }
我不知道这些行是什么意思诚实。
调用堆栈还在调试器中显示while循环行,其中注释:Graph :: ~Graphic(this = 0x90909090,__ in_chrg = optimize out)。我还指出行删除* itr的3倍(带有相同的音符)。
所以我的问题是,我如何破坏我的Graph对象?:'(
编辑:经过进一步的实验,当我删除在向量中添加内容的唯一linein代码时,段错误消失。这是方法。我将补充说,向量中的值总是相同的(不应该)。
void Graph::AddNode(Board& tablo)
{
Graph tmp(tablo, this);
Graph* newChild = &tmp;
children.push_back(newChild); // if i commend this, no segfault
}
我不知道这是两个不同的问题还是push_back是析构函数故障的原因。我认为它是无关的,我预计segfault会消失(当然,如果树只有一个节点,析构函数也没有麻烦来破坏树。)
EDIT2:这段代码不会创建任何段错误,但它并没有真正破坏向量中的所有向量,对吧?我认为这不是因为擦除只会破坏指针而不是对象本身。
while(!children.empty()) {
children.erase(children.begin(),children.end());
delete parent;
delete tab;
}
此外,有了这个,有时程序似乎执行得很好但不会在执行结束时停止。 Debbuger似乎没有找到任何东西
编辑:as ask,Graph的复制构造函数:
Graph :: Graph(const Graph&amp; source){* this = source;}
Graph& Graph::operator=(Graph source)
{
if(this!=source)
{
this->parent = source.parent;
this->tab = source.tab;
// this->seen = source.seen;
while(!source.children.empty()) {
for(unsigned i = 0; i<source.children.size(); i++) {
this->children.at(i) = source.children.at(i);
}
}
}
return *this;
}
答案 0 :(得分:4)
问题是:
delete parent;
您的循环正在强制Graph
拥有其子级的语义。但是通过添加该行,您还可以添加Graph
拥有其父级的语义。你不可能两种方式。这样,您的孩子将在删除您的孩子时删除您的父母。删除delete
应解决您的问题。
更好的方法是根据成员变量明确表达所有权:
struct Graph {
std::vector<std::unique_ptr<Graph>> children;
};
这样,即使不必编写析构函数,一切都会被正确删除!见Rule of Zero
答案 1 :(得分:0)
我同意@Barry那行
delete parent;
不应该在析构函数中存在。
此外,析构函数可以稍微清理一下。
您接到了电话
delete tab;
在while
循环内。无论是否有孩子,都应该在那里打电话。不应该吗?
您也可以完全删除while
循环。
Graph::~Graph() {
// Just loop over the children and delete them.
// If there are no children, the loop is a no op.
for(vector<Graph*>::iterator itr = children.begin(); itr != children.end(); ++itr) {
delete *itr;
}
// No need for this.
// The vector will be deleted anyway.
// children.clear();
// Delete tab regardless of the number of children.
delete tab;
}
答案 2 :(得分:0)
AddNode函数似乎错了。当函数完成时,tmp对象将被销毁,然后向量中的指针变为无效,并在稍后调用delete时导致问题。
使用new代替。也许是这样的:
void Graph::AddNode(Board& tablo)
{
Graph* newChild = new Graph(tablo, this);
children.push_back(newChild);
}
答案 3 :(得分:0)
我将总结我所做的修改及其后果。
我将析构函数更改为@R Sahu和Barry说。
Graph::~Graph() {
for(vector<Graph*>::iterator itr = children.begin(); itr != children.end(); ++itr) {
delete *itr;
}
delete tab;
}
我改变了addNodes,因为nielsen建议(DieterLücking也是如此):
void Graph::AddNode(Board& tablo)
{
Graph tmp(tablo, this);
Graph* newChild = new Graph(tablo, this);
children.push_back(newChild);
}
而且,正如Paul McKenzie所问,这是我的operator =和Graph的复制构造函数。
Graph::Graph(const Graph& source) : parent(source.parent), tab(source.tab) {
while(!source.children.empty()) {
for(unsigned i = 0; i<source.children.size(); i++) {
this->children.at(i) = source.children.at(i);
}
}
}
Graph& Graph::operator=(Graph source)
{
this->parent = source.parent;
this->tab = source.tab;
// this->seen = source.seen;
return *this;
}
这让我想通了operator =不复制向量:'(
现在,如何执行。 Segfault仍在这里,但是callstack发生了很大变化。我在调用堆栈中只有2行,而不是5/6。 callstack告诉我
有问题Board* Graph::gettab(){return this->tab;}
当我这样做时,为了看看graph.children vector中的内容:
for(vector<Graph*>::iterator itr = children.begin(); itr != children.end(); ++itr)
{
tmp = (*itr)->gettab();
Board& test = *tmp; // it's print(Board&) so i just create this. I'll create print(int**) later
print(test);
}
如果我将这些行放在注释中,则段错误仍然存在。 callstack在stl_iterator.h中引用了3行(你需要那些?)以及析构函数中的for循环和delete * itr行。
编辑:
@nielsen你问我的主人。
int main()
{
int lines, columns;
Play game;
Play& jeu = game;
srand(time(NULL));
cout << "+++++++++++++++++++++++++++++" << endl;
cout << "+++ SOLVER +++" << endl;
cout << "+++++++++++++++++++++++++++++" << endl;
cout << endl;
cout << endl;
cout << "Random Board \nLignes : ";
cin >> lines;
cout << "\n Colonnes : ";
cin >> columns;
Board randomTab(lines, columns, jeu);
print(randomTab);
trace(randomTab);
cout << "________________" << endl;
Graph tree(randomTab); /// Call stack point to this !
Board temporary(randomTab);
Board& temp = temporary;
Board* tmp = NULL;
bool controls = false;
vector<int> directions {72,75,77,80};
for(vector<int>::iterator itr = directions.begin(); itr != directions.end(); ++itr)
{
temp = randomTab;
controls = jeu.moves(temp,*itr);
if(controls)
{
cout << *itr << endl;
tree.AddNode(temp);
print(temp);
// trace(temp);
controls = false;
}
}
cout << "__________________" << endl;
vector<Graph*> children = tree.getchildren();
/* for(vector<Graph*>::iterator itr = children.begin(); itr != children.end(); ++itr)
{
tmp = (*itr)->gettab();
Board& test = *tmp;
print(test);
cout << "test";
trace(temporary);
}*/
return 0;
}
Graph::Graph(Board source) : parent(NULL), tab(&source) {} // constructeur pour racine
Graph::Graph(Board source, Graph* grap) : parent(grap), tab(&source) {} // constructeur pour nouvelle feuille
Graph::Graph(const Graph& source) : parent(source.parent), tab(source.tab) { // constructeur par copie
while(!source.children.empty()) {
for(unsigned i = 0; i<source.children.size(); i++) {
this->children.at(i) = source.children.at(i);
}
}
}
答案 4 :(得分:0)
有人问我董事会是如何创建的。在当前的用例中:
Board::Board(int m, int n, Play& jeu) : tab(new int*[m]), nbline(m), nbcolumn(n), emptyspot(n-1,m-1){
int x(1);
for (int i = 0; i < m; ++i){
tab[i] = new int[n];
for(int j = 0; j < n; ++j) {
tab[i][j] = x; x++;}}
tab[n-1][m-1]=0;
x=0;
while (x!=1000)
{
int numbers[] = { UP, DOWN, LEFT, RIGHT };
int length = sizeof(numbers) / sizeof(int);
int randomNumber = numbers[rand() % length];
jeu.moves(*this, randomNumber);
x++;
}
}
/// copy constructor
Board::Board(const Board& origin): tab(NULL), nbline(origin.nbline), nbcolumn(origin.nbcolumn), emptyspot(origin.emptyspot)
{
this->tab = new int*[this->nbline];
for (int i = 0; i < this->nbline; ++i)
{
this->tab[i] = new int[this->nbcolumn];
for (int j = 0; j < this->nbline; ++j)
{
this->tab[i][j] = origin.tab[i][j];
}
}
}
Board::~Board()
{
for(int i = 0; i < this->nbline; i++)
{
delete tab[i];
}
delete tab;
}
Board& Board::operator=(Board& source)
{
if (this != &source)
{
Position pos(0,0);
Position& p=pos;
this->setNbline(source.getNbline());
this->setNbcolumn(source.getNbcolumn());
this->setEmptySpot(source.getEmptySpot());
for (int i =0; i < source.getNbline(); i++)
{
for(int j=0; j < source.getNbcolumn(); j++)
{
p.setposition(i,j);
setValue(p,source.getValue(p));
}
}
}