A problem about Component class


#1

Hi everyone,

I just tried to learn the usage of "addChildComponent" & "removeChildComponent". The code is here:


class A   : public Component
{
public:
    A() {}
    ~A() {}
    void paint (Graphics& g)
    {
        g.fillAll( Colours::black);
    }
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (A)
};
class B   : public Component
{
public:

    B() {}
    ~B() {}
    void paint (Graphics& g)
    {
        g.fillAll( Colours::pink);
    }
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (B)
};

class MainContentComponent   : public Component, public Timer
{
public:
    MainContentComponent() : stamp(0)
    {
        setSize(800, 600);
        a = new A;
        addAndMakeVisible( a);
        a->setBounds(0, 0, 800, 600);
        startTimerHz(60);
    }
    ~MainContentComponent()
    {
        removeChildComponent( b);
        delete b;
    }
    void timerCallback() override
    {
        ++stamp;
        if( stamp >= 60)
        {
            removeChildComponent( a);
            delete a;
            b = new B;
            addAndMakeVisible(b);
            b->setBounds(0, 0, 800, 600);
        }
        repaint();
    }
private:
    int stamp;
    A* a;
    B* b;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};


Then a run-time error will happen. I can't understand why. can anybody help me ?

Thanks!

lgg


#2

Whenever stamp is over 60, it will remove A from the main component and delete it. When stamp is 61, it will remove a deleted A again (probably not the cause of the error, should be ok), but then it will delete A once more. And again. And again.

 

Deleting an object more than once is undefined behaviour. You probably just wanted to execute the code inside "if(stamp >= 60)" once, so call stopTimer() inside there?


#3

There are multiple issues with your example:

 

1. Use ScopedPointers for the member components.

2. Use the resized() method to call setBounds() for the child components

3. Don't use addChildComponent. use addAndMakeVisible() and set the ScopedPointers to nullptr to safely delete them.


#4

Thanks. That's my fault. I fixed the problem like this:


void timerCallback() override
    {
        ++stamp;
        if( stamp >= 60 && a != nullptr)
        {
            delete a;
            a = nullptr;
            b = new B;
            addAndMakeVisible(b);
            b->setBounds(0, 0, 800, 600);
        }
        repaint();
    }


And now it's ok.


#5

Thanks and I attempt to control the component manually and accurately, so i used new/delete.


#6

The #1 golden rule of all modern C++ is never to use 'delete'!!

And do you really want to keep repainting your UI every second?