Background:
So I've been porting some of my older Java code to C++, and I've come across an issue that's making proceeding quite difficult. My project uses a tree data-structure to represent the node hierarchy for 3D animation.
Java:
public final class Node {
private final Node mParent;
private final ArrayList<Node> mChildren;
//private other data, add/remove children / parents, etc ...
}
In Java, its quite simple to create a tree that allows for modification etc.
Problem:
I'm running into issues is with C++, arrays cannot easily be added to without manually allocating a new chunk of memory and having the existing ones moved over so I switched to std::vector. Vectors have the issue of doing what I just described internally making any pointers to there elements invalid. So basically if you wan't to use pointers you need a way to back them so memory holding the actual nodes doesn't move. I herd you can use std::shared_ptr/std::unique_ptr to wrap the nodes in the std::vector, and I tried to play around with that approach but it becomes quite unwieldy. Another option would be to have a "tree" class that wraps the node class and is the interface to manipulate it, but than (for my use case) it would be quite annoying to deal with cutting branches off and making them into there own trees and possibly attaching different branches.
Most examples I see online are Binary trees that have 2 nodes rather than being dynamic, or they have many comments about memory leaks / etc. I'm hoping there's a good C++ alternative to the java code shown above (without memory leak issues etc). Also I won't be doing ANY sorting, the purpose of the tree is to maintain the hierarchy not to sort it.
Honestly I'm really unsure of what direction to go, I've spent the last 2 days trying different approaches but none of them "feel" right, and are usually really awkward to manage, any help would be appreciated!
Edit:
An edit as to why shared_ptrs are unwieldy:
class tree : std::enable_shared_from_this<tree> {
std::shared_ptr<tree> parent;
std::vector<std::shared_ptr<tree>> children;
public:
void set_parent(tree& _tree) {
auto this_shared_ptr = shared_from_this();
if (parent != nullptr) {
auto vec = parent->children;
auto begin = vec.begin();
auto end = vec.end();
auto index = std::distance(begin, std::find_if(begin, end, [&](std::shared_ptr<tree> const& current) -> bool {
return *current == this_shared_ptr;
}));
vec.erase(std::remove(begin, end, index), end);
}
parent = std::shared_ptr<tree>(&_tree);
if (parent != nullptr) {
parent->children.push_back(this_shared_ptr);
}
}
};
working with pointers like above becomes really quite verbose, and I was hoping for a more simple solution.
std::listinstead ofstd::vectorfor a quick and dirty solution. Pointers to list elements are not invalidated if elements from the list are removed. But again, this is quick and dirty if you are ok with using std::list.std::shared_ptr<tree>everywhere is unwieldy, use an alias.