Memory leaks galore


#1

In JUCE 1.23, this worked beautifully:[code]#include <juce.h>

class AudioSettingsDialog : public DialogWindow
{
public:
AudioSettingsDialog (AudioDeviceManager& audioDeviceManager) : DialogWindow (T(“Audio Settings”), Colours::lightgrey, true)
{
centreWithSize (500, 300);

	AudioDeviceSelectorComponent* audioControlComp = new AudioDeviceSelectorComponent (audioDeviceManager, 0, 0, 0, 2, false);
	audioControlComp->setBounds(0, DEFAULTTITLEBARHEIGHT, getWidth(), getHeight()-100);
	addAndMakeVisible (audioControlComp);

	TextButton* m_okay = new TextButton(T("Okay"));
	m_okay->setBounds(getWidth()-180, getHeight()-60, 60, 25);
	m_okay->addButtonListener(this);
	addAndMakeVisible(m_okay);

	TextButton* m_cancel = new TextButton(T("Cancel"));
	m_cancel->setBounds(getWidth()-100, getHeight()-60, 60, 25);
	m_cancel->addButtonListener(this);
	addAndMakeVisible(m_cancel);

	setVisible (true);
	toFront(true);
}
~AudioSettingsDialog()
{
}
void closeButtonPressed()
{
	exitModalState(0);
}
void buttonClicked (Button* button)
{
	exitModalState (button->getButtonText() == T("Okay"));
}

};

class MyApp : public JUCEApplication
{
AudioDeviceManager* dm;

public:
MyApp()
{
}
~MyApp()
{
}
void initialise (const String& commandLine)
{
dm = new AudioDeviceManager;
dm->initialise(0,2,0);
AudioSettingsDialog d(*dm);
if(d.runModalLoop ())
{
// Do something
AlertWindow::showMessageBox(AlertWindow::InfoIcon, T(“Success”), T(“Audio settings successfuly changed.”));

		JUCEApplication::quit();
	}
	else
	{
		JUCEApplication::quit();
	}
}
void shutdown()
{
	delete dm;
}
const String getApplicationName() 
{ 
	return T("MyApp"); 
}
const String getApplicationVersion() 
{ 
	return T("1.0"); 
}

};

START_JUCE_APPLICATION(MyApp)[/code]In JUCE 1.24, I get a ton of memory leaks. If delete the components in the dialog manually, then all is well. Of course, if I put in deleteAllChildren() in the destructor it throws an exception, so I can’t do that. Am I doing something naughty?

  • kbj

#2

yes, you’re doing something very naughty. Never add components directly to a DialogWindow (or any ResizableWindow)!! I’m sure I explained all this in the comments!

In 1.23 it used to just delete all the children of the window - now it only deletes the things that are supposed to be there.


#3

Okay, I figured it might be that. I had looked through the 1.23 DialogWindow and ResizableWindow code to see how important the contentComponent was, and since the only thing it seemed to do was get resized, I thought I could cut some corners and drop components directly onto a ResizableWindow.

Design-wise, what’s the philosphy behind requiring contentComponent to be the only component in a ResizableWindow? Properly redoing the above example makes it a look little more ugly, especially the passing of a parent container pointer to the child so the child can call back to the parent (ugh, horrid!):[code]#include <juce.h>

class AudioSettingsDialogComponent : public Component, public ButtonListener
{
DialogWindow* m_window;

public:
AudioSettingsDialogComponent (AudioDeviceManager& audioDeviceManager, DialogWindow* window) : Component (T(“Audio Settings Component”)), m_window(window)
{
setBounds (0, 0, 500, 300 - DEFAULTTITLEBARHEIGHT);

  AudioDeviceSelectorComponent* audioControlComp = new AudioDeviceSelectorComponent (audioDeviceManager, 0, 0, 0, 2, false);
  audioControlComp->setBounds(0, 0, getWidth(), getHeight()-100);
  addAndMakeVisible (audioControlComp);

  TextButton* m_okay = new TextButton(T("Okay"));
  m_okay->setBounds(getWidth()-180, getHeight()-60, 60, 25);
  m_okay->addButtonListener(this);
  addAndMakeVisible(m_okay);

  TextButton* m_cancel = new TextButton(T("Cancel"));
  m_cancel->setBounds(getWidth()-100, getHeight()-60, 60, 25);
  m_cancel->addButtonListener(this);
  addAndMakeVisible(m_cancel);

}
~AudioSettingsDialogComponent()
{
deleteAllChildren();
}
void buttonClicked (Button* button)
{
m_window->exitModalState(button->getButtonText() == T(“Okay”));
}
};

class AudioSettingsDialog : public DialogWindow
{
public:
AudioSettingsDialog (AudioDeviceManager& audioDeviceManager) : DialogWindow (T(“Audio Settings”), Colours::lightgrey, true)
{
centreWithSize (500, 300);
setContentComponent(new AudioSettingsDialogComponent(audioDeviceManager, this));
setVisible (true);
toFront(true);
}
void closeButtonPressed()
{
exitModalState(0);
}
};

class MyApp : public JUCEApplication
{
AudioDeviceManager* dm;

public:
MyApp()
{
}
~MyApp()
{
}
void initialise (const String& commandLine)
{
dm = new AudioDeviceManager;
dm->initialise(0,2,0);
AudioSettingsDialog d(*dm);
if(d.runModalLoop ())
{
// Do something
AlertWindow::showMessageBox(AlertWindow::InfoIcon, T(“Success”), T(“Audio settings successfuly changed.”));

     JUCEApplication::quit();
  }
  else
  {
     JUCEApplication::quit();
  }

}
void shutdown()
{
delete dm;
}
const String getApplicationName()
{
return T(“MyApp”);
}
const String getApplicationVersion()
{
return T(“1.0”);
}
};

START_JUCE_APPLICATION(MyApp)[/code]This is really much less elegant IMHO. If ButtonListener in DialogWindow was public instead of protected, then I could make it more palatable by adding the parent DialogWindow as the button listener for the Okay and Cancel buttons.

  • kbj

#4

Some of the many reasons are: if all your components are safely inside a content component, they can’t overlap or mess with the border or title bar. Also you don’t have to worry about how big the title bar is to position them. And your components don’t have to share a parent with the resizer component, or the window buttons. And a million other things…

(And you could always use getTopLevelComponent() if you need get the host window)


#5

Although adding a getTitleBarHeight method would be nice. When I subclassed it to do the same thing that DocumentWindow does now, I did a similer workaround. Well, maybe it is not so necessary anymore, but anyway. :slight_smile:


#6

It already has a method that gets the border sizes, including the title bar. getContentBorder() or something.


#7