Вектор возвращает отрицательный размер с ++ - PullRequest
0 голосов
/ 02 мая 2018

Для упражнения я хочу распечатать древовидную структуру данных, основанную на объектах Node. Это означает, что каждый объект имеет векторные узлы, которые снова содержат другие объекты типа Node. Но по какой-то причине, когда я позволяю распечатать this-> get_nr_children из листовых узлов, которые в основном просто возвращают node.size (), я получаю совершенно случайные (отрицательные) целые числа, где он должен фактически возвращать 0. Еще более интересная часть: каждый Когда я компилирую и выполняю, он выводит разные целые числа, которые всегда являются низкими отрицательными числами Я понятия не имею, что происходит!

node.h

#include <string>
#include <vector>

using namespace std;

class Node
{
public:
    virtual ~Node();
    Node(string name = "");
    string get_name() const;
    void set_name(string& new_name);
    int get_nr_children() const;
    Node* get_child(int i) const;
    void add_child(Node child);
    void create_complete_tree(int nr_child_nodes, int tree_depth);
    void print();

private:
    string name;
    static int node_id;
    vector<Node> nodes = {};
};

node.cpp

#include "node.h"
#include <sstream>

using namespace std;

Node::Node(string name) {
    node_id++;
    nodes = {};
    if (name == "") {
        stringstream str_sm;
        str_sm << (node_id);
        string node_id_str = str_sm.str();
        this->name = "node_" + node_id_str;
    } else {
        this->name = name;
    }
}

Node::~Node() {
    nodes.clear();
    // node_id = 0;
}

int Node::node_id = 0;

string Node::get_name() const {
    return name;
}

void Node::set_name(string& new_name) {
    this->name = new_name;
}


int Node::get_nr_children() const {
    return nodes.size();
}

Node* Node::get_child(int i) const {
    if (i >= nodes.size()) {
        return NULL;
    }
    Node node = nodes[i];
    Node *ptrNode = &node;
    return ptrNode;
}

void Node::add_child(Node child) {
    nodes.push_back(child);
}

void Node::create_complete_tree(int nr_child_nodes, int tree_depth) {
    tree_depth--;
    if (tree_depth <= 0) {
        return;
    }
    for (int i = 0; i < nr_child_nodes; i++) {
        Node* node = new Node();
        this->add_child(*node);
        node->create_complete_tree(nr_child_nodes, tree_depth);
    }
}

void Node::print() {
    cout << this->get_name() << "\n";
    cout << "I got this many children " << this->get_nr_children();
    for (int i = 0; i < this->get_nr_children(); i++) {
        cout << "\t";
        this->get_child(i)->print();
        cout << "\n";
    }
}

main.cpp

#include <iostream>
#include "node.cpp"

using namespace std;

    int main() {
        Node* root = new Node("root");
        Node* left_child = new Node("left child");
        Node* right_child = new Node("right child");

        root->add_child(*left_child);
        root->add_child(*right_child);

        root->print();

        return 0;
    }

Когда я выполняю это, я получаю:

root У меня так много детей 2 осталось ребенка У меня столько детей -62802357 правильный ребенок у меня так много детей -62802357

Процесс завершен с кодом выхода 0

Ответы [ 3 ]

0 голосов
/ 02 мая 2018
Node* Node::get_child(int i) const {
    if (i >= nodes.size()) {
        return NULL;
    }
    Node node = nodes[i];
    Node *ptrNode = &node;
    return ptrNode;
}

Выше вы возвращаете указатель на уничтоженный локальный Node node после возврата get_child(i). Ниже приведен правильный код, который возвращает указатель на дочерний элемент в векторе.

Node* Node::get_child(int i) const {
    if (i >= nodes.size()) {
        return NULL;
    }
    return &nodes[i];
}

main может быть реализовано намного проще без указателей и утечек памяти.

int main() {
    Node root("root");

    root.add_child(Node("left child"));
    root.add_child(Node("right child"));

    root.print();

    return 0;
}
0 голосов
/ 02 мая 2018

Ваша проблема проистекает из

this->get_child(i)->print();

get_child возвращает указатель на локальный объект. Этот объект уничтожается, когда функция возвращается, поэтому вызов print для возвращенного Node работает с уже уничтоженным Node.

Что вам нужно сделать, это вернуть указатель непосредственно на элемент вектора, например

Node* Node::get_child(int i) /*const*/ { // cant be const for the return
    if (i >= nodes.size()) {
        return NULL;
    }
    return &nodes[i];
}
0 голосов
/ 02 мая 2018

Проблема с функцией Node* Node::get_child(int i) const. Возвращает указатель на объект, который уничтожается в конце вызова функции.

Node* Node::get_child(int i) const {
    if (i >= nodes.size()) {
        return NULL;
    }
    Node node = nodes[i]; // <- node is a copy of nodes[i]
    Node *ptrNode = &node;
    return ptrNode;       // <- returns a pointer to node
}                         // <- local objects are destroyed, including node

Вы должны вернуть указатель на фактический элемент из вектора.

Node* Node::get_child(int i) const {
    if (i >= nodes.size()) {
        return NULL;
    }
    return  &nodes[i]; // <- Returns the address of the actual node
}
...