【问题标题】:Taking the address of a temporary object of type 'Node'获取“节点”类型的临时对象的地址
【发布时间】:2016-02-01 12:35:04
【问题描述】:

t.PreorderTraversal(t, &t.getRoot()); 错误是获取“节点”类型的临时对象的地址。 Root 是一个 Node 类对象。函数PreoderTraversal将Node对象作为一个点,所以我给出了Node对象的地址并发生了错误。这不是正确的做法吗?

class NodeList;

class Node {
private:
    Node* parent;
    int elem;
    NodeList* children;
    Node *next;
    Node *prev;

};

class NodeList {
public:
    NodeList();
    void addNodeAtRank(int, int);
private:
    Node* header;
    Node* tailer;
};

class Tree {
private:
    int n;
    Node root;
public:
    Tree();
    void addNode(Tree &t, int, int, int);
    void PreorderTraversal(const Tree& t, Node* p);
    void PostorderTraversal(const Tree& t, Node* p);
    void printXYofNode(const Tree& t, int nodeNumber);
    Node getRoot();
    Node* getNodeByElem(Node& n, int);
};

Node::Node() {

    children = nullptr;
    parent = nullptr;
    elem = 0;
    next = nullptr;
    prev = nullptr;

}

NodeList::NodeList() {

    header = new Node();
    tailer = new Node();

    header->next = tailer;
    tailer->prev = header;
}

void NodeList::addNodeAtRank(int rank, int e) {

    Node *v = new Node();
    v->elem = e;

    int count = 1;
    Node *NodeAtRank = header->next;

    while (count != rank) {
        NodeAtRank = NodeAtRank->next;
        count++;
    }

    v->next = NodeAtRank;
    v->prev = NodeAtRank->prev;
    NodeAtRank->prev = v;
    NodeAtRank->prev->next = v;

}

bool NodeList::empty() const {
    return header->next == tailer;
}

Tree::Tree() {

    n = 0;
    //root = Node();
}

void Tree::addNode(Tree& t, int NodeElement, int ParentNode, int SiblingOrder) {

    //Node *treeNode = new Node();

    if (t.empty() && ParentNode == -1 && SiblingOrder == -1) {
        t.root = Node();
        t.root.elem = NodeElement;
        t.root.children = new NodeList();
    } else {

        Node* nodeParent = t.getNodeByElem(t.root, ParentNode);

        NodeList *childrenNodelist = nodeParent->children;
        childrenNodelist->addNodeAtRank(SiblingOrder, NodeElement);

        nodeParent->children = childrenNodelist;
    }

    n++;
}

Node* Tree::getNodeByElem(Node& root, int nodeElem) {

    if (root.elem == nodeElem)
        return &root;
    else {
        NodeList *rootChildren = root.children;

        Node *head = rootChildren->header;

        while (head->next != rootChildren->tailer) {

            if (!head->next->isExternal())
                return getNodeByElem(*(head->next), nodeElem);
            else {
                if (head->next->elem == nodeElem)
                    return head->next;

                head = head->next;
            }
        }

        return new Node();
    }
}

void Tree::PreorderTraversal(const Tree& t, Node* p) {

    cout << p->elem;
    NodeList *mychildren = p->children;
    Node *traversal = mychildren->header->next;

    while (traversal != mychildren->tailer) {
        cout << " ";
        PreorderTraversal(t, traversal->next);
        traversal = traversal->next;
    }

}

void Tree::PostorderTraversal(const Tree& t, Node* p) {

    NodeList *mychildren = p->children;
    Node *traversal = mychildren->header->next;

    while (traversal != mychildren->tailer) {
        PreorderTraversal(t, traversal);
        traversal = traversal->next;
    }
    cout << p->elem;
}

bool Tree::empty() const {
    return n == 0;
}

int Tree::size() const {
    return n;
}

Node Tree::getRoot() {
    return root;
}

int main(int argc, const char * argv[]) {

    char Type = NULL;
    int nodeNumber = 0;
    int nodeParent = 0;
    int nodeOrderInSibling = 0;

    Tree t = Tree();
    cin >> Type;
    while (Type != 'Q') {
        if (Type == 'I') {
            cin >> nodeNumber >> nodeParent >> nodeOrderInSibling;
            t.addNode(t, nodeNumber, nodeParent, nodeOrderInSibling);
        } else if (Type == 'P') {
            t.PreorderTraversal(t, &t.getRoot());
        } else if (Type == 'T') {
            t.PostorderTraversal(t, &t.getRoot());
        } else if (Type == 'C') {
            cin >> nodeNumber;
            t.printXYofNode(t, nodeNumber);
        } else {
            cout << "Wrong input type!!!" << endl;
        }

        cin >> Type;
    }

    return 0;
}

【问题讨论】:

  • 考虑更好地缩进你的代码,现在很难阅读。
  • 你的遍历函数原型很奇怪。为什么要将对 Tree 对象的 const 引用作为参数?这要求您在调用期间指定对象两次t.PreorderTraversal(t, &amp;t.getRoot()); t.PostorderTraversal(t, &amp;t.getRoot()); "this" 是 C++ 中的隐式参数,所以我认为省略 Tree 参数(因为不需要它)或将函数声明为静态会更有意义。

标签: c++ tree xcode5 treenode preorder


【解决方案1】:

变化:

Node Tree::getRoot() {
    return root;
}

到:

Node& Tree::getRoot() {
    return root;
}

否则&amp;t.getRoot() - 返回临时对象的地址,这是未定义行为非法的。

【讨论】:

  • +1 用于在这种情况下将他引导至引用而不是指针,但 -1 因为它不是未定义的行为。这简直是​​违法的。
【解决方案2】:

此函数返回Node 对象的副本,该对象是Tree 的成员

Node getRoot();

因此,在这一行中,您将获得该对象的地址,该地址随后将被丢弃。

t.PreorderTraversal(t, &t.getRoot());

剩下的指针称为悬空指针,因为它不指向有效对象。

考虑像这样修改getRoot

Node* Tree::getRoot() {
    return &root;
}

您当然必须确保Root 对象在您使用此指针时不会超出范围

【讨论】:

    【解决方案3】:

    编译器错误是完全正确的。您正在使用临时地址(这违反了标准)。 Tree::getRoot() 返回一个 Node 类的副本,所以 &t.getRoot() 是一个临时的地址。我认为您的意思是从 getRoot() 返回一个指针。其语法为:

    Node * getRoot();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      相关资源
      最近更新 更多