在调试第二次执行while循环期间,下面的代码会产生out_of_range
异常。我注意到了:
:
在stack.top()之后:
有谁知道为什么会发生这种情况以及如何解决这个问题?
#include <iostream>
#include <stack>
#include <vector>
#include <memory>
#include <functional>
int replacement;
int toreplace;
class Node
{
public:
int id_;
std::vector<Node*> children;
Node* at(int i)
{
return children.at(i);
}
std::vector<Node*> GetChildren() {
return children;
}
Node(int id_) {
this->id_ = id_;
}
};
class CPreorderStackFrame
{
public:
Node* node_;
CPreorderStackFrame* root_;
int index_;
explicit CPreorderStackFrame(Node* node_, CPreorderStackFrame* root_, int index_)
{
this->node_ = node_;
this->root_ = root_;
this->index_ = index_;
}
void replaceChildrenByIndex(Node* replace, int index)
{
replace->id_ = node_->at(index)->id_;
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
}
bool hasChildren() {
return !(node_->GetChildren().empty());
}
};
void pre_order_traverse(Node* root,
std::function<std::unique_ptr<Node>(Node*)> visit)
{ // always: root != NULL
std::stack<CPreorderStackFrame> mystack;
mystack.push(CPreorderStackFrame(root, NULL, NULL));
while (!mystack.empty())
{
CPreorderStackFrame cur = mystack.top();
mystack.pop();
std::unique_ptr<Node> replace = visit(cur.node_);
if (replace)
{
cur.root_->replaceChildrenByIndex(replace.release(), cur.index_);
}
else if (cur.hasChildren())
{
for (int i = cur.node_->GetChildren().size() - 1; i >= 0; --i)
{ //preorder requires right to left
Node *topush = cur.node_->at(i);
if (topush)
{
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame); //hier ist noch alles richtig
}
}
}
}
}
std::unique_ptr<Node> print_visit(Node* node) {
std::cout << node->id_ << ' ';
return NULL;
}
std::unique_ptr<Node> replace_visit(Node* node) {
std::cout << node->id_ << ' ';
if (node->id_ == toreplace) {
std::unique_ptr<Node> retval(new Node(replacement));
return retval;
}
return NULL;
}
int main() {
toreplace = 3;
replacement = 8;
Node *a = new Node(1);
Node *b = new Node(2);
Node *c = new Node(3);
Node *d = new Node(4);
Node *e = new Node(5);
Node *f = new Node(3);
Node *g = new Node(3);
Node *h = new Node(42);
Node *i = new Node(42);
a->children.push_back(b);
a->children.push_back(c);
a->children.push_back(d);
a->children.push_back(e);
b->children.push_back(f);
b->children.push_back(g);
b->children.push_back(h);
b->children.push_back(i);
pre_order_traverse(a, replace_visit);
return 0;
}
答案 0 :(得分:0)
一个问题是
std::vector<Node*> GetChildren()
这意味着
delete node_->GetChildren()[index];
node_->GetChildren()[index] = replace;
正在销毁一个对象,但只是在向量副本中替换它的地址 取消引用原始向量中的元素是未定义的。
您需要通过引用返回,或将删除代码移至Node
。
另一个问题,以及观察的直接原因是
CPreorderStackFrame nextFrame(topush, &cur, i);
mystack.emplace(nextFrame);
存储指向自动对象cur
的指针,其生命周期以迭代结束结束
在此之后取消引用指针是未定义的。
大多数(可能是所有)编译器将在下一次迭代中重用该对象的存储,这意味着您的所有CPreorderStackFrame
存储相同的指针,并且其中没有一个是有效的。你取消引用它的时间。
根本看起来根本不需要指针。