I wish to express that each object of type V owns an object of type B. B is a polymorphic type, and is therefor accessed through a pointer or reference to prevent slicing (C.145). I find it natural to express this as following
class B {};
class V {
public:
unique_ptr<B> p;
};
I can now derive B and assign the derived to p, as such
class D : public B {};
V x;
x.p = make_unique<D>();
Because B is a polymorphic type, it is advised to suppress copies and moves to prevent slicing (C.67).
B(const B&) = delete;
// etc...
It is impossible to copy p, because it's a unique_ptr, and I have now prevented deep copying as well, unless a clone function is implemented (C.130). Is the implementation of a virtual clone function an indication of poor design? It seems like a work-around.
By following these two rules from the C Core Guidelines, I have prevented the copying of V. If V is a vertex in a graph, and graphs must be copied, then I have created a problem for myself; No graphs can be copied anymore. Implementing a custom copy assignment for V doesn't solve that issue, because deep-copying of p is impossible.
After searching around the web, I found no solution which felt natural, and I concluded that there must be something very wrong with my way of thinking. Is it a bad idea to have a polymorphic member? If one should not copy a polymorphic object then one can neither copy any object owning another polymorphic object.
The member can be a shared_ptr instead, but then the semantics become wrong, because this is not a shared object. I lack a way of expressing something that is so obviously simple to conceptualize. How do I copy an object that owns another polymorphic object while not sacrificing semantics? Every post I've read where someone poses a question regarding copying of unique_ptr, deep copying etc..., are usually met with an answer that entails a sacrifice, most likely because the way of solving the problem is wrong in the first place. I have a feeling there is a very simple and elegant solution to this.
CodePudding user response:
You need to ask yourself a question : Why should B not be copyable?
The example you described, with a graph owning one (or probably multiple) vertexes shows the opposite : B should be copyable! What you don't want is two graphs sharing the same vertex instance.
So you can create a copy constructor / clone method for V along those lines :
V::V(const V& other)
{
p = other.p->clone();
}
std::unique_ptr<B> D::clone()
{
return std::make_unique<D>(...);
}
Have a look at this article for a better explanation.