我在Folder类中有这个成员函数:
string _recFullPath() {
list<Folder*> folders;
list<Folder*>::iterator it = folders.begin();
folders.push_front(this);
it = folders.begin();
while((*it)->hasParent()) {
folders.push_front((*it)->parent());
it = folders.begin();
}
folders.push_back(this);
for(it = folders.begin(); it != folders.end(); ++it) {
cout << (*it)->getName() << "/";
}
}
这会编译,但是当涉及到it = folders.begin()时,在while循环中它会产生分段错误,我无法弄清楚原因。 Folder对象的布局如下:
class Folder {
private:
Folder* _parent;
string _name;
string _fullPath;
string _recStrFullPath;
bool _hasParent;
public:
Folder(string name) {
this->_name = name;
this->_hasParent = false;
}
Folder(string name, Folder* parent) {
this->_parent = parent;
this->_name = name;
this->_hasParent = true;
}
Folder* parent() {
return this->_parent;
}
string getName() {
return this->_name;
}
};
当然还有上面提到的功能。有人可以在上面的代码中看到我做错了什么吗?
答案 0 :(得分:1)
我不知道为什么你的while
循环完全使用迭代器。这将更清洁,更简单:
list<Folder*> folders;
Folder* current = this;
while (current->hasParent()) {
folders.push_front(current);
current = current.parent();
}
folders.push_front(current);
for(list<Folder*>::const_iterator i = folders.begin(); i != folders.end(); ++i) {
cout << (*i)->getName() << "/";
}
答案 1 :(得分:0)
在不管理该类存储的情况下,要求在类中使用指针通常不是好的形式。至少,你必须清楚地说明调用者的分配要求应该如何工作。以下是一些代码来说明:
Folder foo(){
Folder bar("bar");
Folder baz("baz", &bar);
return baz;
}
这里发生的事情非常难看,但看起来你做了你应该做的事情。返回时发生的事情是baz被复制到调用者需要去的存储位置,但是baz保留了指向bar的指针。 bar(和原来的baz,你现在有一个副本)都没了,在函数结束时从堆栈中释放出来。
有几种方法可以摆脱这种混乱局面。正确的方法可能是在类本身中完全管理内存。这是另一个版本:
class Folder {
private:
Folder* _parent;
string _name;
string _fullPath;
string _recStrFullPath;
bool _hasParent;
public:
Folder(const Folder & src)
: _name(src._name), _fullPath(src._fullPath)
, _recStrFullPath(src._recStrFullPath)
{
if (src._parent) {
_parent = new Folder(src._parent);
}
}
~Folder() {
delete _parent;
}
Folder(string name) {
this->_name = name;
this->_hasParent = false;
}
Folder(string name, const Folder & parent) {
this->_parent = new Folder(parent);
this->_name = name;
this->_hasParent = true;
}
Folder* parent() {
return this->_parent;
}
string getName() {
return this->_name;
}
};
重要的变化是,在创建子节点时,实际上将父节点复制到子节点中,而不是指针。孩子有自己的副本。它还负责该副本,因此调用者根本不需要关心它。
为了完成这项工作,必须对课程进行一些更改。更改了子构成构造函数的调用签名,以明确父级不受影响。填写_parent时,将使用new
创建副本。
为了方便这一点,有必要添加另一个构造函数,一个复制构造函数,因为我们需要特别关注_parent节点。
最后,由于我们在类本身中执行这些alloc,因此在实例消失时添加析构函数来清理这些alloc是必要的。
现在,来电者可以这样:
Folder foo(){
Folder bar("bar");
Folder baz("baz", bar);
return baz;
}
礼貌地工作。