I am currently implementing some sort of hierarchical structure and I need to assign the parent entity to the child if the child is attached to the parent. My question is, if I could solve this problem using a friend method in the parent class and if this would be good coding style. Here is a short example to explain what I mean:
class Node {
Node* parent;
Node() : parent(nullptr) { }
friend void attachChild(const Node& child) const;
friend void detachChild(unsigned long idx) const;
};
class ListNode : public Node {
std::vector<Node*> childs;
ListNode() : Node() { this->childs = {}; }
void attachChild(Node* child) const {
child->parent = this;
childs.push_back(child);
}
void detachChild(unsigned long idx) const {
child->parent = nullptr;
child.erase(child.begin() + idx)
}
};
class NodeOne : public Node {};
class NodeTwo : public Node {};
class NodeThree : public Node {};
And a last short comment: A child entity could obviously just have one parent entity, whereas the child and parent could be in my scenario of the same type.
YES, in this case it is bad coding style. Typically for heirarchical structures like this, the information about parent/child relationships is kept in the node itself.
The ListNode class is redundant, and it's functionality really belongs to the node itself, which is why you find yourself needing to friend the class.
You can avoid using friend functions by simply adding a setParent method to the node class. If you want to make sure only nodes can mess around with parent/child relationships, make it private/protected.
class Node {
public:
Node() : parent(nullptr) { };
int addChild(Node* child)
{
child->setParent(this);
this->children.push_back(child);
int idx = this->children.size() - 1;
return idx;
};
void removeChild(unsigned long idx)
{
Node* child = children.at(idx);
child->setParent(nullptr);
this->children.erase(children.begin() + idx);
}
private:
void setParent(Node* node)
{
parent = node;
}
private:
Node* parent;
std::vector<Node*> children;
};
example:
int main(int argc, char* argv[])
{
Node parent;
Node child;
parent.addChild(&child);
}
Related
First of all, I want to point out that it is the first time I am using dynamic polymorphism and the composite design pattern.
I would like to use the composite design pattern to create a class Tree which is able to take different objects of the type Tree, a composite type, or Leaf, an atomic type. Both Tree and Leaf inherit from a common class Nature. Tree can store Leaf or Tree objects into a std::vector<std::shared_ptr<Nature>> children. I would like to fill the vector children with a syntax of this kind (so I guess I have to use variadic, to consider a generic number of inputs in the input lists), as in the following:
Leaf l0(0);
Leaf l1(1);
Tree t0;
Tree t1;
t0.add(l0,l1);
t1.add(t0,l0,l1); // or in general t1.add(t_00,...,t_0n, l_00,...,l_0n,t10,...,t1n,l10,...,l1n,.... )
Then I would also access different elements of a Tree by means of the operator[ ]. So for example t1[0] returns t0 and t1[0][0] returns l0, while t1[0][1] returns l0.
Also I would like an homogeneous behaviour. So either use -> or the dot for accessing the methods on all levels (tree or leaf).
Is it possible to achieve this behaviour?
The implementation of such classes can be like the following:
class Nature
{
public:
virtual void nature_method() = 0;
virtual~Nature();
//virtual Nature& operator[] (int x);
};
class Leaf: public Nature
{
int value;
public:
Leaf(int val)
{
value = val;
}
void nature_method() override
{
std::cout << " Leaf=="<<value<<" ";
}
};
class Tree: public Nature
{
private:
std::vector <std::shared_ptr< Nature > > children;
int value;
public:
Tree(int val)
{
value = val;
}
void add(const Nature&);
void add(const Leaf& c)
{
children.push_back(std::make_shared<Leaf>(c));
}
void add(const Tree& c)
{
children.push_back(std::make_shared<Tree>(c));
}
void add(std::shared_ptr<Nature> c)
{
children.push_back(c);
}
template<typename...Args>
typename std::enable_if<0==sizeof...(Args), void>::type
add(const Leaf& t,Args...more)
{
children.push_back(std::make_shared<Leaf>(t));
};
template<typename...Args>
typename std::enable_if<0==sizeof...(Args), void>::type
add(const Tree& t,Args...more)
{
children.push_back(std::make_shared<Tree>(t));
};
template<typename...Args>
typename std::enable_if<0<sizeof...(Args), void>::type
add(const Leaf& t,Args...more)
{
children.push_back(std::make_shared<Leaf>(t));
add(more...);
};
template<typename...Args>
typename std::enable_if<0<sizeof...(Args), void>::type
add(const Tree& t,Args...more)
{
children.push_back(std::make_shared<Tree>(t));
add(more...);
};
void nature_method() override
{
std::cout << " Tree=="<< value;
for (int i = 0; i < children.size(); i++)
children[i]->nature_method();
}
}
I could implement the overload operator [] to return a pointer to Nature or a Nature object, like so:
Nature& operator[] (int x) {
return *children[x];
}
std::shared_ptr< Nature > operator[] (int x) {
return children[x];
}
In both cases, the return type is Nature related. This because it could be a Leaf or a Tree, which is not known in advance. But since the return type of the operator has to be known at compile time, I cannot do something else.
However, if the returned type would be Tree related, I cannot use the operator [] anymore, because I have enforced it to be Nature.
How can I dynamically choose the return type, Tree or Leaf related, of []? Is there any workaround for this?
I could consider operator [] a virtual method in the Nature class, but still I would no what to make out of this.
I have read about covariant types as well, but I do not know if they would be applicable here.
Thank you.
If you want to be type-safe, the return value of [] will have to be checked at each use site to determine if it is a Tree or a Leaf.
You could also choose not to be type-safe, and invoke undefined behaviour if you use a Leaf in a way that is supposed to be a Tree.
Regardless:
virtual Nature& operator[](std::ptrdiff_t i) {
throw std::invalid_argument("Not a Tree");
}
virtual Nature const& operator[](std::ptrdiff_t i) const {
throw std::invalid_argument("Not a Tree");
}
in Nature, followed by:
virtual Nature& operator[](std::ptrdiff_t i) final override {
auto r = children.at((std::size_t)x);
if (r) return *r;
throw std::out_of_range("no element there");
}
virtual Nature const& operator[](std::ptrdiff_t i) const final override {
auto r = children.at((std::size_t)x);
if (r) return *r;
throw std::out_of_range("no element there");
}
in Tree.
That'll spawn exceptions when you use [] on the wrong type.
I am trying to attach bits of data, called components, to an Entity node.
However, whenever I attach a derived component type to the Entity node, it is being upcasted to the base Component type instead of staying a child. How could I prevent this so I can make use of std::type_index?
Currently, because the Component is being upcasted, std::type_index keeps making an index for Component, rather than one of the child classes. Do I have to template out the AttachComponent method? I'd rather not.
class Entity final
{
//Typedefs
typedef std::map<std::type_index, std::shared_ptr<acorn::Component> > ComponentMap;
ComponentMap m_components;
unsigned long int m_ID;
private:
public:
explicit Entity(unsigned long int id);
~Entity();
//Getters
inline unsigned long int GetID() const
{
return m_ID;
}
template<class ComponentType>
std::weak_ptr<ComponentType> GetComponent()
{
auto component_map_it = m_components.find(std::type_index(typeid(ComponentType)));
//If the component was found
if (component_map_it != m_components.end()) {
//Get the shared_ptr of the component
std::shared_ptr<acorn::Component> base_ptr = component_map_it->second;
//Cast it to the desired component type
std::shared_ptr<ComponentType> converted_ptr(std::static_pointer_cast<ComponentType>(base_ptr));
//Convert to a weak pointer
std::weak_ptr<ComponentType> return_ptr(converted_ptr);
//Return the weak pointer
return return_ptr;
}
else {
//If no component type was found, return a nullptr.
return std::weak_ptr<ComponentType>();
}
}
//Setters
inline void AttachComponent(std::shared_ptr<Component> component)
{
auto raw_ptr = component.get();
auto insert_pair = std::make_pair(std::type_index(typeid(raw_ptr)), component);
m_components.insert(insert_pair);
}
};`
Yes, you have to make AttachComponent a template. That's the only way to preserve the type information:
template <class T>
void AttachComponent(std::shared_ptr<T> component)
{
// as before
}
When we implement lock-free data structures, why do we need to manage memory? Consider the following stack example, why does the "delete old_head" statement in the pop function , as the book say, cause problems to other threads? I don't see chances that "dereferencing a dangling pointer" can happen, and I run the code several times, not getting any error.
template<typename T>
class lock_free_stack
{
private:
struct node
{
std::shared_ptr<T> data;
node* next;
node(T const& data_) :
data(std::make_shared<T>(data_))
{}
};
std::atomic<node*> head;
public:
void push(T const& data)
{
node* const new_node = new node(data);
new_node->next = head.load();
while (!head.compare_exchange_weak(new_node->next, new_node));
}
std::shared_ptr<T> pop()
{
node* old_head = head.load();
while (old_head &&
!head.compare_exchange_weak(old_head, old_head->next));
auto res = old_head ? old_head->data : nullptr;
delete old_head;
return res;
}
};
First of all, there's no such built in concept as "interface". By interface in C++, I really mean some abstract base class that looks like:
struct ITreeNode
{
... // some pure virtual functions
};
Then we can have concrete structs that implement the interface, such as:
struct BinaryTreeNode : public ITreeNode
{
BinaryTreeNode* LeftChild;
BinaryTreeNode* RightChild;
// plus the overriden functions
};
It makes good sense: ITreeNode is an interface; not every implementation has Left & Right children - only BinaryTreeNode does.
To make things widely reusable, I want to write a template. So the ITreeNode needs to be ITreeNode<T>, and BinaryTreeNode needs to be BinaryTreeNode<T>, like this:
template<typename T>
struct BinaryTreeNode : public ITreeNode<T>
{
};
To make things even better, let's use unique pointer(smart point is more common, but I know the solution - dynamic_pointer_cast).
template<typename T>
struct BinaryTreeNode : public ITreeNode<T>
{
typedef std::shared_ptr<BinaryTreeNode<T>> SharedPtr;
typedef std::unique_ptr<BinaryTreeNode<T>> UniquePtr;
// ... other stuff
};
Likewise,
template<typename T>
struct ITreeNode
{
typedef std::shared_ptr<ITreeNode<T>> SharedPtr;
typedef std::unique_ptr<ITreeNode<T>> UniquePtr;
};
It's all good, until this point:
Let's assume now we need to write a class BinaryTree.
There's a function insert that takes a value T and insert it into the root node using some algorithm(naturally it will be recursive).
In order to make the function testable, mockable and follow good practice, the arguments need to be interface, rather than concrete classes. (Let's say this is a rigid rule that cannot be broken.)
template<typename T>
void BinaryTree<T>::Insert(const T& value, typename ITreeNode<T>::UniquePtr& ptr)
{
Insert(value, ptr->Left); // Boooooom, exploded
// ...
}
Here's the problem:
Left is not a field of ITreeNode! And worst of all, you cannot cast a unique_ptr<Base> to unique_ptr<Derived>!
What's the best practice for a scenario like this?
Thanks a lot!
Ok, over-engineering it is! But note that, for the most part, such low level data structures benefit HUGELY from transparency and simple memory layouts. Placing the level of abstraction above the container can give significant performance boosts.
template<class T>
struct ITreeNode {
virtual void insert( T const & ) = 0;
virtual void insert( T && ) = 0;
virtual T const* get() const = 0;
virtual T * get() = 0;
// etc
virtual ~ITreeNode() {}
};
template<class T>
struct IBinaryTreeNode : ITreeNode<T> {
virtual IBinaryTreeNode<T> const* left() const = 0;
virtual IBinaryTreeNode<T> const* right() const = 0;
virtual std::unique_ptr<IBinaryTreeNode<T>>& left() = 0;
virtual std::unique_ptr<IBinaryTreeNode<T>>& right() = 0;
virtual void replace(T const &) = 0;
virtual void replace(T &&) = 0;
};
template<class T>
struct BinaryTreeNode : IBinaryTreeNode<T> {
// can be replaced to mock child creation:
std::function<std::unique_ptr<IBinaryTreeNode<T>>()> factory
= {[]{return std::make_unique<BinaryTreeNode<T>>();} };
// left and right kids:
std::unique_ptr<IBinaryTreeNode<T>> pleft;
std::unique_ptr<IBinaryTreeNode<T>> pright;
// data. I'm allowing it to be empty:
std::unique_ptr<T> data;
template<class U>
void insert_helper( U&& t ) {
if (!get()) {
replace(std::forward<U>(t));
} else if (t < *get()) {
if (!left()) left() = factory();
assert(left());
left()->insert(std::forward<U>(t));
} else {
if (!right()) right() = factory();
assert(right());
right()->insert(std::forward<U>(t));
}
}
// not final methods, allowing for balancing:
virtual void insert( T const&t ) override { // NOT final
return insert_helper(t);
}
virtual void insert( T &&t ) override { // NOT final
return insert_helper(std::move(t));
}
// can be empty, so returns pointers not references:
T const* get() const override final {
return data.get();
}
T * get() override final {
return data.get();
}
// short, could probably skip:
template<class U>
void replace_helper( U&& t ) {
data = std::make_unique<T>(std::forward<U>(t));
}
// only left as customization points if you want.
// could do this directly:
virtual void replace(T const & t) override final {
replace_helper(t);
}
virtual void replace(T && t) override final {
replace_helper(std::move(t));
}
// Returns pointers, because no business how we store it in a const
// object:
virtual IBinaryTreeNode<T> const* left() const final override {
return pleft.get();
}
virtual IBinaryTreeNode<T> const* right() const final override {
return pright.get();
}
// returns references to storage, because can be replaced:
// (could implement as getter/setter, but IBinaryTreeNode<T> is
// "almost" an implementation class, some leaking is ok)
virtual std::unique_ptr<IBinaryTreeNode<T>>& left() final override {
return pleft;
}
virtual std::unique_ptr<IBinaryTreeNode<T>>& right() final override {
return pright;
}
};
Consider the following parent/child object model. The intention is for both the parent and the child to use shared_ptr to manage their lifetimes. The parent should keep a shared_ptr to (retain) its children, and the children will keep a weak_ptr to the parent.
Given that the intention is for these objects to always be managed by std::shared_ptr what is the best way to construct them? The method I've come up with (so far) feels a little clunky: I'm using factory (friend) functions and a private constructor to reduce the likelihood that raw pointers to these objects "escape". Then, the child creates a shared_ptr with this in the ctor, and puts that into the parent's vector of children. When the ctor returns the raw pointer to the factory function, the factory function uses shared_from_this() to get a shared_ptr that is "hooked up to" (i.e. sharing a reference count with) the shared_ptr that's in the parent's vector of children.
Here's what I've come up with so far:
class Child; // Forward decl
class Parent : std::enable_shared_from_this<Parent> {
public:
int value() const { return _value; };
void set_value(int newValue) { _value = newValue; };
std::vector<std::shared_ptr<const Child>> children() const {
// propagate const-ness to the child pointers we hand back.
return std::vector<std::shared_ptr<const Child>>(begin(_children), end(_children));
};
std::vector<std::shared_ptr<Child>> children() {
return _children;
};
private:
Parent(int value) : _value(value) {};
friend class Child; // So it can add itself to the _children vector
friend class std::shared_ptr<Parent>; // So that I don't have to inherit public from enable_shared_from_this
friend std::shared_ptr<Parent> CreateParent(int value); // So it can call the private ctor
std::vector<std::shared_ptr<Child>> _children;
int _value;
};
class Child : std::enable_shared_from_this<Child>
{
public:
int value() const { return _value; };
void set_value(int newValue) { _value = newValue; };
private:
Child(const std::shared_ptr<Parent>& parent, int value) : _parent(parent), _value(value) {
std::shared_ptr<Child> sp(this); // This feels wrong, but the existence of the shared_ptr in the parent's vector of children ensures that the precondition for calling shared_from_this() is met
parent->_children.push_back(sp);
};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value); // So it cal call the private ctor
friend class std::shared_ptr<Child>; // So that I don't have to inherit public from enable_shared_from_this
std::weak_ptr<Parent> _parent;
int _value;
};
std::shared_ptr<Parent> CreateParent(int value) {
return std::shared_ptr<Parent>(new Parent(value));
};
std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value) {
std::shared_ptr<Child> rv = (new Child(parent, value))->shared_from_this();
return rv;
};
This seems to work, but man, does it feel clunky. Is there a better way?
I'd do it this way:
class Child;
class Parent {
public:
std::vector<const Child*> children() const {
// propagate const-ness to the child pointers we hand back.
// ...
}
const std::vector<std::unique_ptr<Child>>& children() {
return _children;
}
std::shared_ptr<Parent> create() {
// I'd rather use std::make_shared() here but it needs public ctor
return std::shared_ptr<Parent>(new Parent());
}
std::unique_ptr<Child>& createChild() {
_children.emplace_back(new Child(this));
return _children.back();
}
private:
Parent();
std::vector<std::unique_ptr<Child>> _children;
};
class Child
{
private:
Child(Parent* parent) : _parent(parent) {}
friend class Parent;
Parent* _parent;
};
I stripped out the "value" boilerplate for clarity. I also tried to use the minimal sophistication level of smart pointers that seemed viable to get the job done. I may not have gotten it 100% perfect for your specific use case, but you should think about more clearly defined lifetime/ownership semantics. Having everything sharing everything is sort of a mess and leads to lack of clarity...having clear ownership can make things simpler. And since the Parent class still manages the lifetime of each Child, there's no need to have a fancy pointer from Child back to Parent--a raw pointer will work because the Child won't outlive the Parent.
Given your description of the uncomfortable split of the parent/children management, you can simplify as follows,
class Child;
class Parent {
private:
Parent() {};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
std::vector<std::shared_ptr<Child>> _children;
};
class Child {
private:
Child(const std::shared_ptr<Parent>& parent) : _parent(parent) {};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
std::weak_ptr<Parent> _parent;
};
std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent) {
auto child = std::shared_ptr<Child>(new Child(parent));
parent->_children.push_back(child);
return child;
}
Also notice that there is no shared_from_this here, maybe it is necessary for your other purposes, but it isn't necessary to manage the parent-child relationship.