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