Popup's MenuWindow crash

Could it simply be an additional bool argument for the WeakReference template, which tells whether it should assert when the referenced object gets deleted while the WeakReference is still in existence?

Alternatively, a AssertingWeakReference may be inherited from WeakReference adding that behavior

Hmm, still mumbling about this, I wonder whether the fact that the asserting reference is “weak” is important:

if one desires the reference to assert when the object is deleted, then the intended relationship is not “weak” at all in the intended sense, and such “AssertingReference” would be a helpful tool not because it becomes null, but because it asserts in the moment the pointer goes dangling, rather than the first time one attempts to use it.

The fact that one such AssertingReference would become null could probably be of no help in this case anyway: since it would express a relationship with an object that should exist at all times during the lifetime of the reference itself (hence the assertion if it doesn’t), attempts to use the reference after the object has been deleted will cause a crash anyway, either because the pointer is dangling or because it has been nullified.

So, perhaps the “weak” behavior of your proposed reference could be ditched altogether, and only the part that asserts if the referenced object is deleted could be kept, perhaps only in debug mode so that there is no overhead in using them in release mode

I think I’ve got quite a simple solution for this. IMHO the ideal behaviour is that in debug, you’ll get an assertion when the L+F is actually deleted, which is way more useful than finding out when the dangling pointer is being used. And in a release build, it may draw oddly, but won’t actually crash, at the expense of very little extra overhead. Will push something soon…

Yes, that’s what I said:

Sorry, yes, I was mainly thinking aloud rather than trying to claim it was my idea! :slight_smile:

1 Like

Following your ref counting of LnF, I always have issue for the default LnF (the one set with uce::LookAndFeel::setDefaultLookAndFeel) as there is always
a ref on it.
I delete this global LnF using a DeleteAtShutdown
Any idea how to solve this ?

Thanks !

Well, you’d need to call setDefaultLookAndFeel (nullptr) before your L+F object gets destroyed

Pretty sure you will get quite a lot of annoyed people with this mod as basically as soon as you store your LnF in the component that uses it, you will need to explicitely call setLookAndFeel(nullptr) which feel a but unnatural even though I understand the rationale behind it.

Well maybe. Perhaps it should just make a special-case exception so that it won’t assert if the only reference is the global default one.

Didn’t mean the global one in my previous post but all the time you store an LnF as a member in a component to have a custom LnF on it.

No, I think that if you do that, then you should be forced to clear the custom lookandfeel in your object’s destructor.

1 Like

I’m running into asserts about this when it was never a problem before…

Basically I have a ListBox which uses a custom L&F on the scrollbar:

class member:

 ScopedPointer<ScrollLookAndFeel>   m_pLook;

and in the ListBox ctor:

 m_pLook = new ScrollLookAndFeel();
 getVerticalScrollBar().setLookAndFeel (m_pLook);

If I don’t explicitly remove the L&F from the Scrollbars in my ListBox dtor:

 MyListBox::~ MyListBox()
 {
     getVerticalScrollBar().setLookAndFeel (nullptr);
 }

I’m getting this assertion… Can you disable this “feature”?

(And I’m getting it in more than one location in my plug-in… which means I’ll have to spend time fixing a non-issue in a large code base with multiple L&F’s scattered all over it).

Can I send y’all a bill for the hours it’s taking me to add all these new destructors to my code?

Thanks,

Rail

@Rail_Jon_Rogut If it helps any, we’re using a global pool for look and feel instances, where this pool is deleted at shutdown.

This helped through the adoption of this newer way, with the plus of reducing a tiny amount of memory usage.

Or… they could just remove this assert and let the developers have personal responsibility

I have a boatload of components scattered throughout my project using custom L&F’s and not a single one of them has ever tried to use a dangling pointer… but so far I’ve spent the equivalent of a JUCE license in time tracking down every instance and creating new destructors and setting the L&F to nullptr… and I’m still not done!

Rail

Perhaps you can tell me why this is asserting?

It happens if I have ComboBox and I show and dismiss the popup menu and then quit.

I can get past it if I explicitly delete the ComboBox in the dtor.

Rail

My guess is that the parent class contains something like this:

struct ParentComp
{
    ComboBox box;
    MyLookAndFeel lf;
};

… so that the l+f object will be destructed before the combobox, which is still using it? If that’s what’s happening then you’d just need to reverse the order of declarations.

Yes, but I was still getting the assert after having

 box.setLookAndFeel (nullptr);

in the destructor which I thought would have negated the variable order.

Cheers,

Rail

Yeah, that sounds a bit odd. Could you post a minimal code example that shows this happening?

Just create a Plug-in with PJ, and add a ComboBox and a LookAndFeel:

 /*
    ==============================================================================

     This file was auto-generated!

     It contains the basic framework code for a JUCE plugin editor.

    ==============================================================================
 */

 #pragma once

 #include "../JuceLibraryCode/JuceHeader.h"
 #include "PluginProcessor.h"


 //==============================================================================
 /**
 */
  class Test5AudioProcessorEditor  : public AudioProcessorEditor
 {
  public:
     Test5AudioProcessorEditor (Test5AudioProcessor&);
     ~Test5AudioProcessorEditor();

     //==============================================================================
     void paint (Graphics&) override;
     void resized() override;

  private:
     // This reference is provided as a quick way for your editor to
     // access the processor object that created it.
     Test5AudioProcessor& processor;

     ComboBox        m_Combo;
     LookAndFeel_V4  m_Look;


     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Test5AudioProcessorEditor)
 };

and

/*
   ==============================================================================

    This file was auto-generated!

    It contains the basic framework code for a JUCE plugin editor.

   ==============================================================================
*/

#include "PluginProcessor.h"
#include "PluginEditor.h"


//==============================================================================
 Test5AudioProcessorEditor::Test5AudioProcessorEditor (Test5AudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    // Make sure that before the constructor has finished, you've set the
    // editor's size to whatever you need it to be.
    setSize (400, 300);

    m_Combo.setBounds(10, 10, 100, 30);

    addAndMakeVisible (m_Combo);

    m_Combo.setLookAndFeel (&m_Look);

    m_Combo.addItem("One", 1);
    m_Combo.addItem("Two", 2);
    m_Combo.addItem("Three", 3);
}

 Test5AudioProcessorEditor::~Test5AudioProcessorEditor()
{
    m_Combo.setLookAndFeel (nullptr);
}

//==============================================================================
 void Test5AudioProcessorEditor::paint (Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));

    g.setColour (Colours::white);
    g.setFont (15.0f);
    g.drawFittedText ("Hello World!", getLocalBounds(), Justification::centred, 1);
}

 void Test5AudioProcessorEditor::resized()
{
    // This is generally where you'll want to lay out the positions of any
    // subcomponents in your editor..
}

If you change the variable order you get rid of the assert as expected… but setting the L&F to nullptr doesn’t (which I thought odd).

To test, build as Debug, run and open and close the ComboBox PopupMenu without selecting anything a few times… then quit.

Cheers,

Rail

OK, thanks, I see what’s going on there, will push a fix soon.