Am 08.08.21 um 15:17 schrieb HIV:
If we swap those two lines, i.e. if we already have deleted those objects
through the filerlist.clear(), then strange enough the filerscroll->clear()
does *not* invoke the dtor of the FilterLine objects again.

Hi all,

meanwhile, to investigate that, I have installed the debug-info package and
was able to step througth the FTLK code with the debugger. Matters are pretty much straight forward.

- FilerLine inherits from FL_Group
- but the FL_Scoll also inherits from FL_Group

Both the FL_Scrikk::clear() as well as the dtor of FL_Group invoke the
relevant method FL_Group::clear()



/**
  Deletes all child widgets from memory recursively.

  This method differs from the remove() method in that it
  affects all child widgets and deletes them from memory.
*/
void Fl_Group::clear() {
  savedfocus_ = 0;
  resizable_ = this;
  init_sizes();

  // we must change the Fl::pushed() widget, if it is one of
  // the group's children. Otherwise fl_fix_focus() would send
  // lots of events to children that are about to be deleted
  // anyway.

  Fl_Widget *pushed = Fl::pushed();     // save pushed() widget
  if (contains(pushed)) pushed = this;  // set it to be the group, if it's a 
child
  Fl::pushed(this);                     // for fl_fix_focus etc.

  // okay, now it is safe to destroy the children:

#define REVERSE_CHILDREN
#ifdef  REVERSE_CHILDREN
  // Reverse the order of the children. Doing this and deleting
  // always the last child is much faster than the other way around.
  if (children_ > 1) {
    Fl_Widget *temp;
    Fl_Widget **a = (Fl_Widget**)array();
    for (int i=0,j=children_-1; i<children_/2; i++,j--) {
      temp = a[i];
      a[i] = a[j];
      a[j] = temp;
    }
  }
#endif // REVERSE_CHILDREN

  while (children_) {                   // delete all children
    int idx = children_-1;              // last child's index
    Fl_Widget* w = child(idx);          // last child widget
    if (w->parent()==this) {         // should always be true
      if (children_>2) {             // optimized removal
        w->parent_ = 0;                      // reset child's parent
        children_--;                    // update counter
      } else {                          // slow removal
        remove(idx);
      }
      delete w;                         // delete the child
    } else {                            // should never happen
      remove(idx);                      // remove it anyway
    }
  }

  if (pushed != this) Fl::pushed(pushed); // reset pushed() widget

}



Moreover, the dtor of FL_Widget also checks if the widget has still a parent
and automatically hides and detaches the widget from the UI.


Thus...
 - if we directly delete the FilteLine objects in the list, each FilterLine
   object's dtor is invoked, which in turn detaches *and deletes* all child
   widgets of this FilterLine instance. So there is no need to delete those
   manually. /The existing code is thus already correct/ (no leaks here!)

 - next, when we invoke filerscroll->clear(), its children_ count is already
   zero, and thus nothing further happens.

Otherwise, if we swap those lines...
 - already the filerscroll->clear() detects the presence of the children and
   detaches and *deletes* all attached child objects together with all nested
   child widgest
 - if we then invoke filerlist.clear(), this will in turn invoke the dtor
   of all contained FilerList instances, which is a double free and (depending
   on the circumstances) can cause a segfault.


Conclusion: the code in the proposed form works and is correct.
However, it would also be possible to do away with that vector/list/deque
alltogether and just hand over the FilerLine widgets to the FL_Scroll,
which will thus manage and clear up the storage automatically.

-- Hermann




_______________________________________________
Yoshimi-devel mailing list
Yoshimi-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/yoshimi-devel

Reply via email to