Is FLTK performing automatic memory de-allocation of dynamically created objects?

109 views
Skip to first unread message

Pierre Rouleau

unread,
Sep 25, 2022, 9:14:08 PM9/25/22
to fltk.general
Hi all,


I'm very new to FLTK.  
For FLTK 1.3.8,
I'v seen documentation and discussion show how easy it is to dynamically create widgets as in:

       Fl_Button *fluidButton = new Fl_Button(25, 80, 70, 50, "button2");

but did not see much code where those dynamically allocated objects are freed (deleted) in destructors.

I would assume that the objects allocated by ``new`` statements would have to be freed by corresponding ``delete`` statements in destructors.  I can understand that it's not that important in the main() function of a program since once it terminates all process memory will be reclaimed by the C++ library code and process termination but for other classes that might be located else where and could be created during the execution a long-running program I would think that not freeing the widgets is just bad practice and memory leaks.

Am I missing something?  

Thanks

/Pierre

Ian MacArthur

unread,
Sep 26, 2022, 3:57:04 AM9/26/22
to fltk.general
The key point is that the fltk container widgets (typically groups or windows, or derivatives thereof) will reap all of their children when they are themselves destroyed.
So if a window is deleted or goes out of scope, it will also remove all of its children. (Though if you want a widget to persist after its parent container is removed you can explicitly remove the child widget from the parent before disposing of the parent, of course...) 
This is in the docs somewhere - I know I've read it!
(A rider to this is that you sometimes need to be aware NOT to delete widgets that have already been deleted by their parent...)

Another point is that it is often, at least with fltk, cheaper to hang onto "temporary" widgets you have created, to use them again later, rather than instantiating them and deleting them all the time as you go along, since many "temporary" widgets actually get used many times during the lifetime of the program, and the retained footprint of a hidden widget in fltk is generally pretty small.

So, it turns out that explicitly deleting the widgets may not be needed, in many cases - there will always be cases where a widget really is transient and used only once, and in that case deleting it explicitly will reduce memory usage and is correct, but there are a lot of cases where just hanging on to the widget and using it again later is faster and cheaper overall.

Tradition (in this list) dictates that at this point I trot out my anecdote, so here we go: Some (now many) years ago, we had a placement student, fresh from college, working for us. To get him familiar with the code he was set to refactoring one of the the support tools. Whilst doing this, he added explicit deletes for every widget that was created with new, because that was what they were taught at school.
This made absolutely no difference whatsoever to the runtime behaviour of the program - but it did trigger a flood of complaints from the end-users.
The previous version of this tool would exit "instantly" when it was closed. 
The "improved" version would take "several minutes" (well, long enough for the users to notice and complain, anyway!), as it trudged it's way through all the explicit destructor stages.

He was made to go back and take out the explicit destructors, and was enlightened.

The point being that explicitly deleting everything that is "new" is not always necessary, and can have surprising negative consequences in some cases.

Manolo

unread,
Sep 26, 2022, 4:14:25 AM9/26/22
to fltk.general
Hi Pierre,

One key information is that the destructor of an Fl_Group also deletes all the group's children :

Now, because FLTK widgets are placed in Fl_Window's and Fl_Window's are Fl_Group's,
when a window is deleted, all the widgets it contains are deleted too.

Another key information is that when you click on the close button of a window,
the window's default close operation occurs which is to call Fl_Window::hide().
This operation does not delete the window (nor its children). The benefit of that
is that you can call Fl_Window::show() later and the window and its children will
reappear. If you need to completely delete a window when its close button is clicked,
you have to change the window's callback, with Fl_Window::callback(), and assign it
a new callback function that does delete the window. At that point, all widgets contained
in the window will get deleted too.

Here is the relevant code to change the window's callback :

static void delete_when_closed(Fl_Widget *win, void *data) {
  Fl::delete_widget(win);
}

// elsewhere in the code where the window is created
  Fl_Window *win = ……
  win->callback(delete_when_closed, NULL); // change the window's callback


Pierre Rouleau

unread,
Sep 26, 2022, 8:08:54 AM9/26/22
to fltk.general
On Monday, September 26, 2022 at 4:14:25 AM UTC-4 Manolo wrote:
Hi Pierre,

Hi Manolo, thanks for the answer.
 
One key information is that the destructor of an Fl_Group also deletes all the group's children :

Now, because FLTK widgets are placed in Fl_Window's and Fl_Window's are Fl_Group's,
when a window is deleted, all the widgets it contains are deleted too.


Ok, but if you have code that creates a pointer to a FL_button with new, like the following, don't you have to register that FL_Button somewhere so that it is know as a member?  Is the new operator overridden by FLTK?

        Fl_Button *fluidButton = new Fl_Button(25, 80, 70, 50, "button2"); 

/Pierre

Pierre Rouleau

unread,
Sep 26, 2022, 8:21:37 AM9/26/22
to fltk.general
On Monday, September 26, 2022 at 3:57:04 AM UTC-4 Ian MacArthur wrote:
On Monday, 26 September 2022 at 02:14:08 UTC+1 Pierre wrote:

For FLTK 1.3.8,
I'v seen documentation and discussion show how easy it is to dynamically create widgets as in:

       Fl_Button *fluidButton = new Fl_Button(25, 80, 70, 50, "button2");

but did not see much code where those dynamically allocated objects are freed (deleted) in destructors.

I would assume that the objects allocated by ``new`` statements would have to be freed by corresponding ``delete`` statements in destructors.  I can understand that it's not that important in the main() function of a program since once it terminates all process memory will be reclaimed by the C++ library code and process termination but for other classes that might be located else where and could be created during the execution a long-running program I would think that not freeing the widgets is just bad practice and memory leaks.

Am I missing something?  

The key point is that the fltk container widgets (typically groups or windows, or derivatives thereof) will reap all of their children when they are themselves destroyed.
How does FLTK class that has a straight member pointer to a widget know to delete that widget at destruction time?  Does FLTK override the operator new?

 
So if a window is deleted or goes out of scope, it will also remove all of its children. (Though if you want a widget to persist after its parent container is removed you can explicitly remove the child widget from the parent before disposing of the parent, of course...) 
This is in the docs somewhere - I know I've read it!
(A rider to this is that you sometimes need to be aware NOT to delete widgets that have already been deleted by their parent...)
 
And it becomes important to understand how their parent delete them.  Which is what I am after.   I don't see how the parent could delete a widget unless there is a tie somewhere between the parent and its widget.  


Another point is that it is often, at least with fltk, cheaper to hang onto "temporary" widgets you have created, to use them again later, rather than instantiating them and deleting them all the time as you go along, since many "temporary" widgets actually get used many times during the lifetime of the program, and the retained footprint of a hidden widget in fltk is generally pretty small.

So, it turns out that explicitly deleting the widgets may not be needed, in many cases - there will always be cases where a widget really is transient and used only once, and in that case deleting it explicitly will reduce memory usage and is correct, but there are a lot of cases where just hanging on to the widget and using it again later is faster and cheaper overall.
Or used only for a given situation that may repeat.  If the code does not pre-allocate the widget *once* but allocates it every time the processing needs to be done then you'd have a leak based on the use of the program, no?

wea...@gmail.com

unread,
Sep 26, 2022, 8:54:10 AM9/26/22
to fltk.general
Hi

Usually you add widgets to somekind of group (Fl_Group, Fl_Window, Fl_Pack, ...). You can add a widget to a group several ways, one way is to use the group's begin() (can be omitted sometimes) and end() functions. I have seen how it works internally, but already forgotten :) If you're interested you can check the Fl_Group::array() function as a starting point. See documentation: https://www.fltk.org/doc-1.3/classFl__Group.html#ab5a03e490bb0dc19f8da7e3e4acdca17

imm

unread,
Sep 26, 2022, 8:58:11 AM9/26/22
to General FLTK
On Mon, 26 Sept 2022 at 13:38, Pierre Rouleau wrote:
>
> How does FLTK class that has a straight member pointer to a widget know to delete that widget at destruction time? Does FLTK override the operator new?
>

No, it's more that the constructor for the fltk widgets adds them to
the active container widget. So when you create a widget it is always
added to the current container.
Thus any container widget, when it is discarded, has a list of its
current children.

Albrecht Schlosser

unread,
Sep 26, 2022, 9:06:44 AM9/26/22
to fltkg...@googlegroups.com
No, the new operator is not overridden by FLTK, and yes, you need to register the button as a child of its parent group. But this is usually done automatically.

Every FLTK container widget (derived from Fl_Group) calls `begin()` in its constructor. This registers it as the "current group". If you create a new widget like in your code above, the constructor of that widget "registers" it as a child of the "current group" by calling something like `Fl_Group::current()->add(this);` i.e. the new widget adds itself to the "current group" as a child widget. This is necessary to handle events and draw the children of the container anyway.

A very simple example is test/hello.cxx which creates a window and a button that is implicitly added to the window. If you look at the code you will also see `window->end();` before the window is shown to disable further automatic adding of widgets to this Fl_Window (Fl_Group).

Of course you can also disable this automatism and add/remove widgets to Fl_Group widgets explicitly, but this is another story.

Pierre Rouleau

unread,
Sep 26, 2022, 9:31:04 AM9/26/22
to fltk.general
Ahhhh.  That make sense.  Thank you!! 
One more question: if the contractor does not call the end member function, does this mean that the 'automatic' registration of widgets continue to operate inside calls to other member function of that class?
 

Pierre Rouleau

unread,
Sep 26, 2022, 10:06:04 AM9/26/22
to fltk.general
contractor-> constructor in my previous question.
So: if the constructor does not call the `end()` member function, does this mean that the 'automatic' registration of widgets continue to operate inside calls to other member function of that class?

Ian MacArthur

unread,
Sep 27, 2022, 6:04:02 AM9/27/22
to fltk.general
On Monday, 26 September 2022 at 15:06:04 UTC+1 Pierre wrote:

So: if the constructor does not call the `end()` member function, does this mean that the 'automatic' registration of widgets continue to operate inside calls to other member function of that class?

When you create a container widget (typically a window or a group) then the container begin() is (implicitly) called and makes this container the "current" parent container. The constructor for the container does not call end().

Any widgets created after that point are then instantiated as children of that container.
Once all the widgets are created, you should then call   

    my_container->end();  

to explicitly "close" that container. 
Though if you only have one window, say, you can often get away without that end() call, and a lot of toy examples you'll see do not have it.

If you are constructing multiple windows it makes a difference whether you end() one window before creating another or not, so it is important to get that bit right!
If you do not end(); the first window before creating the second, then win2 can end up as a subwindow of win1, which (whilst a valid usage) may not be what was intended in many cases.

FWIW, I usually call   

    my_container->begin();

explicitly in my code, even though it is not usually necessary, just to remind future-me that this is what is happening...



Philip Rose

unread,
Sep 27, 2022, 8:15:51 AM9/27/22
to fltkg...@googlegroups.com

 

 

Sent from Mail for Windows

/Pierre

 

 

Hi Pierre,

 

Yes, the constructor for the Fl_Group (or derivative) sets a (global?) current group pointer. The constructor for Fl_Widget then adds itself to an array within the current group. Also the group’s begin() will make that group the current group and its end() remove it. Hence you have to be careful with using end(). Forgetting it or calling it too many times can result in widgets going missing.

 

Phil.

--
You received this message because you are subscribed to the Google Groups "fltk.general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/a0b3b18f-5b2d-420b-a7de-c22308a5391en%40googlegroups.com.

 

Reply all
Reply to author
Forward
0 new messages