Reputation: 671
I am implementing a simple Tree class to use in a parser, where I need to traverse the structure of the parse tree and build it up incrementally.
This is a stripped-down version of the class that demonstrates the issue (executable in this repl.it session):
template <typename T>
class Tree {
T val;
std::deque<Tree<T>> children;
public:
Tree() {}
Tree(T value) : val(value) {}
Tree(T value, std::deque<Tree<T>> children) : val(value), children(children) {}
std::deque<Tree<T>> getChildren() { return this->children; }
void appendChild(T value) {
this->children.push_back(value);
// this->children.emplace_back(value);
std::cout << "Appended child to node with value " << this->val << ".\n";
printChildren();
}
void printChildren() {
std::cout << "children for " << this << "(" << this->val << ")"
<< ": { ";
for (auto &child : this->children) {
std::cout << &child << "(" << child.val << ") ";
}
std::cout << "}\n";
}
};
For each node, the children are stored in a std::deque
so children can be added to either end. In testing my class, I am finding that I cannot rely on the structure produced by building up the tree incrementally as opposed to all-at-once with an initializer list.
Here's some code to exercise the class and show what's happening:
std::cout << "Constructing Tree\n\n";
Tree<int> t(1);
t.appendChild(2);
t.getChildren()[0].appendChild(3);
std::cout << "\n\nPrinting tree from main\n\n";
t.printChildren();
t.getChildren()[0].printChildren();
This has the following output:
Constructing Tree
Appended child to node with value 1.
children for 0x7ffe9fd41820(1): { 0xb69080(2) }
Appended child to node with value 2.
children for 0xb694a0(2): { 0xb696b0(3) }
Printing tree from main
children for 0x7ffe9fd41820(1): { 0xb69080(2) }
children for 0xb698c0(2): { }
As you can see, the addresses of the node with the value 2
are different each time they are printed out. When it's first appended to the 1
node, it has the address 0xb69080
. After it gets its own children, it has the address 0xb694a0
. Then, when it's accessed from the main
function, it has the address 0xb698c0
.
Additionally, it seems that when it gets moved it somehow loses its children. The last line should show that the 2
node has a single child with value 3
.
What's going on here?
Upvotes: 0
Views: 98
Reputation: 66200
I suppose your problem is here
std::deque<Tree<T>> getChildren() { return this->children; }
getChildren()
return a copy of children.
Try with
std::deque<Tree<T>> & getChildren() { return this->children; }
// .................^
to return a reference to the internal children
, if you want modify it using the returned value.
I mean: if getChildren()
return a copy of children
, with
t.getChildren()[0].appendChild(3);
you append a child with value 3
to the first element of the copy of children
returned by getChildren()
.
This copy isn't saved so it's a temporary value that is destroyed immediately after, losing the 3
child appended.
Upvotes: 4