GUI Editor Subcomponents & ScopedPointer

sliderattachment

#1

Hey all.

I just put together a simple GUI for my plugin with the Introjucer Component Editor. I added a bunch of sliders, which the Introjucer adds to the class as ScopedPointer<Slider> members. I’ve also added a ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> manually for each slider, linking the slider to a particular value in my processor’s ValueTreeState.

When my editor destructor is called, I get a reference error when JUCE’s ContainerPolicy tries to delete something that has already been deleted. This only happens in Windows, actually, and I can’t figure out why.

The problem goes away when I list my slider members directly as Slider types rather than as ScopedPointer<Slider> types, but I can’t find a way to make the GUI editor add my sliders in this way.

Is there some obvious solution that I’m missing? Or will I have to just stop using the GUI editor?

Thank you!


#2

It’s very difficult to work out what’s happening if you don’t provide any code. The quickest way to a solution is to create the shortest possible piece of code that displays the problem - this way it’s much easier for someone else to see what might be going wrong. Usually this involves stripping your application or plug-in back to something extremely simple, and in the process it’s likely that you’ll discover what the issue is anyway!


#3

Thanks @t0m, yea I suppose I didn’t give you much to go on. I’ve found a fix for the problem, but it makes me question whether or not there’s a difference in the Windows implementation vs the OS X implementation of the JUCE SliderAttachment. Here’s what I learned:

class MainComponent  : public Component
{
public:
    //==============================================================================
    MainComponent (AudioProcessorValueTreeState& vts);
    ~MainComponent();

    void paint (Graphics& g) override;
    void resized() override;

private:
    ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> filterFreqAttachment;
    ScopedPointer<Slider> m_cutoffSlider;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

In this scenario, I get an error when this component’s destructor is called because m_cutoffSlider gets destroyed from a loop in the Component class destructor, which destroys all child components. Afterwards, my filterFreqAttachment gets destroyed, and when it does, it tries to remove the Listener it has attached to m_cutoffSlider, which yields an error because it tries to refers to m_cutoffSlider's ListenerList, which has already been destroyed.

I’ve worked around the problem by explicitly setting filterFreqAttachment = nullptr; first thing my ~MainComponent() destructor method so that the listener removal happens before the Slider destruction. This works fine for me, but what’s curious is that if I don’t have that line in my destructor, I still see no problems on OS X. Only on Windows do I get that null pointer reference.

That’s all I’ve got so far, but I’ve resolved the error so feel free to ignore :slight_smile:

Thanks


#4

The easiest would be to swap the members filterFreqAttachment and m_cutoffSlider. Usually the members are destroyed in the same sequence, but you did well in that case to enforce the destruction sequence by setting the attachment to nullptr defore the slider gets destroyed.
I don’t know if there is a strict rule, that the members are destroyed in the same order as they are defined, might be, that the compiler has some freedom here…?


#5

there’s no freedom for compilers to do this - destruction is the opposite of construction


#6

That’s good to know, that this is always the case, thanks.

…and reading myself again, sure I meant opposite… silly me…


#7

Yes but I’m not sure destruction order is the only factor at play here; the Component class destructor seems to include a while loop that runs through all child components and deletes them. I actually tried switching the order of my member definitions here before I realized I could explicitly set nullptr and it still didn’t work. Although it very well could have been something else entirely that I just missed :stuck_out_tongue:


#8

You must be referring to this:

while (childComponentList.size() > 0)
    removeChildComponent (childComponentList.size() - 1, false, true);

But you are being confused here: what happens here is that child Components are only removed from the Component being destructed, they aren’t deleted because of that.

Removal of a child Component from its parent simply means that their parent-child relationship is discarded, which means:

  • the parent removes the pointer to the child from the list of its children

  • the child sets its pointer to a parent component to null (it becomes an orphan, available for addition to a different parent component if you want to do that)

That’s why it is common to hold pointers to child Components as ScopedPointer members in the parent: since the destructor of the parent doesn’t delete them automatically, they instead get automatically deleted when their corresponding ScoperPointer members are destroyed, which would not happen if you were referring to them with simple pointers (e.g. Component*, Button* etc.).


#9

Ah I see. Thanks @yfede, indeed I was mistaken!