LookAndFeel assert firing on 5.2 quit


#1

Hi, I’m now getting an assert because my main.cpp void closeButtonPressed() is deleting the object defaultLookAndFeel = 0.
My look and feel stuff is all made and destroyed in mainComponent constructor and destructor.
The assert is called when defaultLookAndFeel = 0; in main of the standard audio app.

    LookAndFeel::~LookAndFeel()
    {
         jassert (masterReference.getNumActiveWeakReferences() == 0
                  || (masterReference.getNumActiveWeakReferences() == 1
                       && this == &getDefaultLookAndFeel()));
    }

Juce - xCode - setLookAndFeel - error
LookAndFeel assert firing with ComboBoxPopup open
#2

I see that main.cpp has changed quite a bit, but using the new one still makes the assert somewhere else.


#4

When copy + pasting the code above, you seem to have chosen to delete the big, explanatory comment that I put there to tell you what’s going on!

LookAndFeel::~LookAndFeel()
{
    /* This assertion is triggered if you try to delete a LookAndFeel object while it's
         - still being used as the default LookAndFeel; or
         - is set as a Component's current lookandfeel; or
         - pointed to by a WeakReference somewhere else in the code

       Deleting a LookAndFeel is unlikely to cause a crash since most things will use a
       safe WeakReference to it, but it could cause some unexpected graphical behaviour,
       so it's advisable to clear up any references before destroying them!
    */
    jassert (masterReference.getNumActiveWeakReferences() == 0
              || (masterReference.getNumActiveWeakReferences() == 1
                   && this == &getDefaultLookAndFeel()));
}

That explains why it’s firing - you’re deleting the L+F while something still has a reference to it!


#5

I’ve tried many ways, even not deleting them at all, and leaving them for them as a class member. Please note the defaultLookAndFeel = 0 was set even before it got to my mainComponent destructor.
Where am I supposed to delete the lookandfeel, if not in the mainComponent destructor?


#6

First call

setDefaultLookandFeel (nullptr);

Then you can delete it. Right now your mainComponent still references it. With the setDefaultLookandFeel call, you remove that reference and thus you are free to delete it.


#7

OK, lost so much time with this one. So, to wrap up, call setLookAndFeel(nullptr); at the end of your plug-in editor’s destructor.


#8

Thank-you.


#9

For anyone that has a bit more complex scenario and has multiple LookAndFeel classes to change the application theme - you need to set the used (by the components tree) L&F to nullptr on every change not only in the destructor and only after that to delete the old L&F.

Basically you need to detach it from the components and THEN delete it.

I’ve been debugging for 5h, now, so here is a little something to hopefully save someone some precious time:

// PluginEditor.h
class PluginEditor :    public AudioProcessorEditor
{
    //...
private:
    ScopedPointer<LookAndFeel> lookAndFeel;
    // ...
};


//==============================================================================


// PluginEditor.cpp
// ...
PluginEditor::~PluginEditor()
{
    // if this is missing - YOU WILL HIT THE ASSERT
    setLookAndFeel (nullptr);
    // ...
}

// ...

void PluginEditor::selectTheme ()
{
    // if this is missing - YOU WILL HIT THE ASSERT
    setLookAndFeel (nullptr);

    const String themeName = getThemeNameFromSomewhere ();

    if (themeName == "X")
    {
        lookAndFeel = new LookAndFeel_X ();
    }
    else
    {
        lookAndFeel = new LookAndFeel_Y ();
    }

    setLookAndFeel (lookAndFeel);
}

setLookAndFeel (nullptr) triggers an assert failure in findColour ()
#10

Thanks! I was also dealing with the same problem but setDefaultLookandFeel (nullptr); in the destructor worked for me.

This issue was still a bit confusing to me even with the assert comment (which I do greatly appreciate!). It might be beneficial to specify in that assert comment that you can remove a Component’s LookAndFeel reference with setDefaultLookandFeel (nullptr);. This was just a bit counter intuitive to me since I assumed as a Component is destroying itself, it would handle the removal of its LookAndFeel.

Thanks!


#11

Thanks Tim, I tried to make the comment as clear as possible but good idea, I’ll add a note about calling setDefaultLookandFeel (nullptr)

No, that’s the opposite of what this assertion is telling you! The problem is not that a LookAndFeel is being leaked, it’s a warning that a L+F is being deleted before all components have stopped using it.


#12

Thanks Jules! That is clear to me now from your assert comment.

Thanks for all you and your team’s hard work on JUCE! JUCE has been so empowering for me and I feel that I am now a better C++ programmer because of it. I’ve been sharing it with all my friends too. JUCE is a joy to use and learn from.


#13

How about adding a comment alluding to this?


#14

Thanks, I’ll add that.