0

How can I improve architecture of my code? I have feeling that something is wrong with the idea to delete object by call to its void remove() { delete this; } method.


I have hierarchy (I call it hierarchy1) of objects in my program. Each object in hierarchy can contain one or multiple objects of other classes. Example:

class A { std::vector<std::unique_ptr<B>> bs; };
class B { std::unique_ptr<C> c; };
class C { std::unique_ptr<D> d; std::vector<std::unique_ptr<E>> es; };
class D {};
class E {};

I also have orthogonal hierarchy (I call it hierarchy2). It is hierarchy of objects, which are not contatining any data, but instead behave as a representation of some of basic objects with data. The connection between objects in this hierarchy is established through signal/slot pattern. Example:

class C { 
    std::unique_ptr<D> d; std::vector<std::unique_ptr<E>> es;
    Signal changed;
    void change(); // somehow changes data and emits signal changed
};
class D { 
    Signal changed;
    void change(); // somehow changes data and emits signal changed
}; 
class C1 { 
    C1(C* c) { c->changed.connect(this, &C1::change); }; 
    Signal changed;
    void change(); // updates its local state based on changes in class C and emits own "changed" signal
}
class C1D {
    C1D(C1* c1, D* d) {
        c1->changed.connect(this, &C1D::change);
        d->changed.connect(this, &C1D::change);
    }; 
    Signal changed;
    void change(); // updates its local state based on changes in class C1 and/or D and emits own "changed" signal
}

This hierarchy works very well in the sense that I can initiate any modification in any class and it firstly will go down in hierarchy2 (for example from C1 to C) and later it will go up, updating all representations (which depend on C).

The only doubt in the correctness of architecture arises when I start to think about deletion of objects. I want to do essentially the same as modification, so instead of function and signal pair "change" I introduce function and signal pair "remove". So the idea is that when I call for example c1->remove() it should pass request to remove down to class C, class C at this time will initiate signal to force removal of each of its representations (C1, C1D) and finally class C will ask its parent B to reset std::unique_ptr<C> c; therefore causing self-destruction.

How can I improve this architecture? I believe it is not common pattern when I have pointer to object C* c = ..., call c->remove(), object is actually destroyed and pointer can't be used.

  • Questions asking for improvements to otherwise-working code are off-topic for StackOverflow. They should be asked on [Code Review](http://codereview.stackexchange.com) instead. – Remy Lebeau Jun 09 '18 at 19:58
  • @RemyLebeau I didn't provide existing working code, just pseudocode examples. My question not about improving code, but about improving architecture, because I can't decide am I going in a right direction. If question seems unclear or broad, I can help to understand by giving next types of possible answers: 1. this is perfectly valid pattern and used in a lot of production code. (examples) 2. this architecture has flaws (examples) and you should use ??? instead. I'm sorry if I am wrong and it is really offtopic. –  Jun 09 '18 at 20:03
  • @IgorTandetnik You absolutely right. I assume `delete this` as a different name to `c.reset()` to make question clear since the first paragraph. –  Jun 09 '18 at 20:06

1 Answers1

1

How can I improve this architecture? I believe it is not common pattern when I have pointer to object C* c = ..., call c->remove(), object is actually destroyed and pointer can't be used.

The object exists until the destructor returns, so while in the destructor you can still use it. The following is perfectly legal:

class C 
{
  Signal destroyed (C *);

  ~C() 
  {
    destroyed (this);
  }
}

Qt does it (it has a destroyed() signal) and I have written self-updating tree structures this way.

Two comments, though:

  • Why create a remove() function when C++ has a perfectly legal way to destroy an object by the delete operator?
  • If you must have a function, I would suggest calling it destroy() in stead of remove(); the latter suggest removal from lists etc. without actual destruction.
JvO
  • 3,036
  • 2
  • 17
  • 32
  • 1
    1. I create `remove()` because my objects use inheritance and I want to issue signal `removed` in base class before deletion of child classes part of object to be able to call virtual methods. 2. I actually use two methods: `destroy` and `remove`. `destroy` makes `delete this`, while `remove` goes down in hierarchy asking for deletion. So that is why I come up to this problem and want to understand is it a good practice to `delete this`. –  Jun 09 '18 at 20:46