1

In tree, while taking input (inside takeInput function), tree node was made using dynamic allocation, but I tried doing it statically, but as tree node were declared inside a function locally it should have not worked because its a local variable (I was expecting a error). But Why am I able print it even after that:

NOTE: this code takes input recursively (and may not be the best way)

#include<bits/stdc++.h>
using namespace std;
template <typename T>
class treeNode{
    public:
    T data;
    vector <treeNode<T>> children;
    treeNode(T data){
        this->data=data;
    } 
};
treeNode<int> takeInput(){
    int rootdata;
    cout<<"Enter Node"<<endl;
    cin>>rootdata;
    // treeNode<int>* root= new treeNode<int>(rootdata);

    treeNode<int> root(rootdata);   //Static Allocation

    cout<< "Enter Number of children of "<<rootdata<<endl;
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        treeNode<int> child = takeInput();
        root.children.push_back(child);
    }
    return root;
}
void printTree(treeNode<int> root){
    cout<<root.data<<": ";
    for(int i=0;i<root.children.size();i++){
        cout<<root.children[i].data<<",";
    }
    cout<<endl;
    for(int i=0; i<root.children.size();i++){
        printTree(root.children[i]);
    }
}
int main(){
    treeNode<int> root= takeInput();
    printTree(root);
    return 0;
}

Following code is using dynamic allocation:

#include<bits/stdc++.h>
using namespace std;

template <typename T>
class TreeNode{
    public:
    T data;
    vector <TreeNode<T>*> children;
    TreeNode(T data){
        this->data=data;
    }
};
TreeNode<int>* takeInput(){
    int rootdata;
    cout<<"Enter node"<<endl;
    cin>>rootdata;
    TreeNode<int>* root=new TreeNode<int>(rootdata);
    cout<<"Enter number of children of "<<rootdata<<endl;
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        TreeNode<int>* child=takeInput();
        root->children.push_back(child);
    }
    return root;
}
void printTree(TreeNode<int>* root){
    if (root == NULL){
        return;
    }
    cout<< root->data<<" :";
    for(int i=0;i<root->children.size(); i++){
        cout<<root->children[i]->data<<",";
    }
    cout<<endl;
    for(int i=0;i<(*root).children.size();i++){
        printTree(root->children[i]);
    }
}
int main(){
    TreeNode<int>* root = takeInput();
    printTree(root);
    return 0;
}
Suryansh Singh
  • 1,123
  • 7
  • 15
  • 1
    Because it's being copied into the return value? – Zoso Jul 31 '21 at 13:18
  • 1
    Nitpick about terminology: you're not doing anything *statically*, you're doing *locally*. It's not static allocation, it's automatic allocation. – rustyx Jul 31 '21 at 13:22
  • @Zoso So I am keep returning it recursively to my root, until whole tree is formed, is that what's happening? So what was the need of using dynamic allocation in this particular case or just our choice? – Suryansh Singh Jul 31 '21 at 13:22
  • 2
    There is dynamic allocation in both examples, its just that it is hidden in the first example behind `std::vector`. The purpose of `std::vector` is to take care of your memory management for you so you don't have to worry about it, to the point that it looks like there isn't anyone. The second example adds a useless second level of dynamic memory management that is harmful. The first example is better and the preferred approach in modern C++. – François Andrieux Jul 31 '21 at 13:34

1 Answers1

1

Your code is equivalent to

A foo() {
    A a;
    a = bar();
    return a;
}

a is just copied into the return value (That copy might be avoided too). Replace A with treeNode<int> and the semantics remain the same.

Why then the dynamic code?

I'm guessing the code version using dynamic allocation was probably coded up thinking that something like

struct A {
    std::vector<A> vecA;
};

is a recursive definition for A since when vecA is declared A is an incomplete type. But that's not the case anymore and this is officially into C++17 (though it worked for some compilers in earlier versions too) where some STL containers can do with incomplete type. Hence it used the form

vector <TreeNode<T>*> children;

storing pointers to the children and hence that code, which is similar to the familiar LinkedList Node data structure definition

struct Node {
    int data;
    Node* next; // The TreeNode stores a vector of pointers instead.
};

Conclusion

Stack allocation is usually preferred when possible since it's faster than the heap route. Also, that code with dynamic allocation brings in the headache of memory management unless smart pointers are being used. It's just not needed for your code. Go with the stack allocation route for your example and let std::vector take care of maintaining the dynamic array.

Zoso
  • 3,273
  • 1
  • 16
  • 27