6

Okay c/c++ megaminds, I have a question about how something is generally designed that I feel like is too broad for SO or to be effectively Googled (though my Google-Jitsu may just be a tad weak, idk)

Lets say I have, for example, a simple graphical interface system where each widget/ control may have child controls. We could store it as a simple list/ array/ vector/ whatever - say Widget.children

Now these children could be added with a function like addChild(Widget*). This function would accept widgets allocated both on the stack and on the heap... but only widgets allocated on the heap would need to be freed.

My question is: on the destructor of the parent widget, how would it free all of its child widgets, if some are on the stack and some are on the heap and we don't know which is which...

And my broader question is what's the general design for this sort of thing? Should all items just be heap allocated always? Should it never be the responsibility of the parent widget to free the child widgets?

Comments
  • 5
    Outlaw stack-residing widgets.
  • 5
    Smells like an awful design. Do not mix entities with different lifetimes.

    And why are pointers to stack based entities even used if their lifetime is pretty short and they could become invalid before your list reaches its end of life? That's basically asking for trouble.
  • 1
    @iiii Imagine the situation where you want to remove a table from view. You remove the widget and every row in the table is a child widget. How do you make sure everything is freed correctly? This is common in things like HTML
  • 4
    @AlgoRythm you don't mix things, so you don't have the problem you've described in the first place. Either the container controls all of its possessions or not. There's no in-between.
  • 2
    I'm not saying you should do this, just that you could use an abstract parent class then either a reference or smart pointer in the base class, bundled as a list of smart pointers. But as said, it'd all be heap allocated.
  • 2
    If you're going to transfer ownership, you should use smart pointers. But generally you just shouldn't transfer ownership. Instead, you should have the widget instantiate its children in a generic method and return a reference. That way it's not possible to abuse the API in this way. There's still the problem of use after free, but that's sort of an omnipresent problem in C++, like nullpointer in Java.
  • 1
    I'm not good at C++, I tried to adapt my ideas of good API design for the feature set I've seen in my limited experience with C++. Can some of the aces verify that what I've said isn't too detached?
  • 3
    I think the parent should free its child nodes. To me an object being the child of another object means it should take ownership over that object.

    I'm not sure why you would need these nodes to be on the stack though?
    Like what benefit does it give you practically?

    You would have to differentiate somehow between the two cases, which I guess you would have to do with addChild() and another addChildFromStack(), which leaves a lot of room for human error.

    If you want to mix the lifetimes of the children, I think you could achieve this with a shared_ptr. When the parent gets destroyed it destroys the shared_ptr, and if that was the last shared pointer to that object it gets cleaned up as well.
    I'm not a entirely huge fan of smart pointers but I think they have their uses.
  • 4
    1) if you can determine the range of memory addresses for the stack you can just compare the pointer arithmetically
    2) if you allocate the memory yourself you can wrap it in a structure that tells you how you allocated it
    3) neither of these things are good programming practice for building GUIs. Unless there’s a REALLY special case you’re handling (and if so I’m sorry for making assumptions) there is no justifiable reason to allocate memory for GUI widgets on the stack
Add Comment