std :: stack.top()更改元素的成员(这是一个指针)

时间:2016-10-25 11:29:40

标签: c++ c++11 pointers

在调试第二次执行while循环期间,下面的代码会产生out_of_range异常。我注意到了:

在stack.top()之前

enter image description here

在stack.top()之后

enter image description here

有谁知道为什么会发生这种情况以及如何解决这个问题?

#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;
}

1 个答案:

答案 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存储相同的指针,并且其中没有一个是有效的。你取消引用它的时间。

根本看起来根本不需要指针。