The short answer to your question, like the others, already answered: "Yes, calling each destructor is problematic, because this is likely to lead to undefined behavior .
For example, look at this situation:
- A
Vertex object v is deleted, - which
m_edge 1st Edge in the m_edge member m_edge , - which
m_head both m_head and m_tail Vertex , - Assuming one of them is
v , the next loop in v destructor will try to access the remote data!
At best, your program will be segfault; in the worst case ... who knows ...
Your design is not so bad. His problem, however, is that you cannot clearly define ownership (which could help to know who should destroy whom).
In fact, assuming that Vertex can be associated with several (and at least one) Edge and that Edge is in relation to exactly two Vertex , then you can assume that Edge belongs to a pair of Vertex . It is not so easy to control the deletion order in this situation ...
However, you do not necessarily need an attitude of ownership of the state, which should destroy anyone. As suggested above, a Edge matches exactly two Vertex ; if one of them is destroyed, then Edge must also be destroyed. On the other hand, if Edge destroyed, there is no reason to destroy any of Vertex in relation to it, because each of them can still be associated with another existing Edge ; the only exception to this is that Vertex has nothing to do with any Edge . The code following these rules is as follows:
struct Edge; struct Vertex { public: // ctors unchanged ~Vertex(); // implemented below void remove_relation(Edge* edge) // for use by Edge only { std::vector<Edge*>::iterator it = std::find(m_edge.begin(), m_edge.end(), edge); if (it != m_edge.end()) m_edge.erase(it); if (m_edge.size() == 0) delete this; // this Vertex can be safely deleted } string m_name; vector<Edge*> m_edge; }; struct Edge { public: // ctors unchanged ~Edge() { // Only have to remove relation with m_head & m_tail if (m_head) m_head->remove_relation(this); if (m_tail) m_tail->remove_relation(this); std::cout << "deleted Edge " << this << std::endl; } void delete_from_vertex(Vertex* from) // for use by Vertex only { // Prevent from removing relation with the calling Vertex if (m_head == from) m_head = nullptr; else if (m_tail == from) m_tail = nullptr; else assert(false); // Vertex not in relation with this Edge delete this; // finally destroy this Edge } string m_name; Vertex* m_head; Vertex* m_tail; }; Vertex::~Vertex() { for(int i = 0; i < m_edge.size(); i++) m_edge[i]->delete_from_vertex(this); // special destruction std::cout << "deleted Vertex " << this << std::endl; }
Living example
source share