What are JUCE's pointer ownership policy?


#1

I’m wanting to clarify something, when you create a new heap allocated instance of a component, say MyComponent, and then add it to the parent component, who is responsible for freeing the MyComponent instance, the creating client code, or the parent component?

Are there any general guidelines/policies that one should be aware of?


#2

With components it’s never the parent that deletes child components, as that’d make it too inflexible for some purposes.

But in general there’s no rule, as it really depends on the context. Whenever there’s a non-const pointer being passed into a method I try to make sure I explain in the comments whose responsibility it is to delete it.


#3

I suggest to use auto_ptr to clarify transferring of ownership:


#4

Well that’s not always what you want to do though - you very often want the caller to also keep a pointer to the object, even if it’s no longer responsible for deleting it.


#5

deleteAllChildren() works for me. Never had to transfer ownership of a Component mind.

OT: This component model is ace Jules. I’ve got this dynamic interactive fretboard showing chords and shit. I use a big one mostly for display and editing but today I put a heap in a custom listbox. They’re so cute! Tiny! But readable. Same fucking class! Woohoo! I could make them editable too but thats overkill.

(sorry)

klf


#6

yeah, i love the component model. it’s top-of-cool-easy-in-world to make exciting compound components. and then they’re reusable! making widgets is too much fun


#7

Oy, no joke, wish other’s used that style, by far the best.


#8

But not in this case:

JUCE::ProgressBar * get_pb(void)
{
	static JUCE::ProgressBar pb(pb_d);
	return &pb;
}

P.S. I think call to _CrtDumpMemoryLeaks (in JUCEApplication::shutdownAppAndClearUp) should be replaced to _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); because at this point some objects are still alive.


#9

Wouldn’t recommend using static components… Best way to do it is to make them a Singleton, and also inherit from DeletedAtShutdown.

And I just tried your debug thing, but it doesn’t work - don’t know why, but it even seems to stop the debug dump working at all…


#10

May it be:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

also _CRTDBG_MAP_ALLOC must be defined.


#11

Ah - that seems to work. Cheers!


#12

How caller would know if object is deleted?

P.S. there are many “delete this;” statements. It is pretty obvious why it is evil: http://comp.uark.edu/~vchaudh/old_home_page/repository/c.html. plus one more problem - in case of multiple copies of CRT (specific for Windows app with dll’s linked statically to CRT) you may delete object from wrong heap.


#13

I mean that something else might be in charge of deleting both objects. E.g. I very often have components that take a pointer to thier parent component, so that they can interact with it. The child will always be deleted by the parent so it’s perfectly safe. But you couldn’t do this with an auto_ptr. I’m sure there are lots of other situations like that too.

I think it’s one of those topics where you could discuss the philosophical niceties of it forever, but in real life it doesn’t cause any problems.

What I WOULD find useful would be some kind of smart pointer that zeros itself when the object it points to gets deleted by something else. Sadly that’s a bit tricky, but it’d be damned useful in Component.cpp, where I’ve had to create the ComponentDeletionWatcher class to do something similar.

[quote]
P.S. there are many “delete this;” statements. It is pretty obvious why it is evil: http://comp.uark.edu/~vchaudh/old_home_page/repository/c.html. plus one more problem - in case of multiple copies of CRT (specific for Windows app with dll’s linked statically to CRT) you may delete object from wrong heap.[/quote]

good point about the shared DLLs. I’d not thought of that.

But checking through the library, almost all of the times it’s used are safe, because they’re mostly used for temporary objects that were created by code inside the juce library, so the allocator will always be the same.

The only one I spotted that could be a problem was in DialogWindow, if an app creates a subclass with a different allocator and presses the close button. I’ll have a think about that. The rest look fine to me.


#14

Watching ComponentDeletionWatcher class I found:

bool Component::isValidComponent() const throw()
{
    return (this != 0) && isValidMessageListener();
}

What (this != 0) does and when this expression becomes false?

Code from BubbleMessageComponent::timerCallback:

setVisible (false);

if (deleteAfterUse)
    delete this;

not exception safe. Since setVisible is virtual it may throw and “this” will newer be deleted, causing “bubble leak”.


#15

(this == 0) means that it still works if you call isValidComponent on a null pointer. (It’d also work without the test, but is more efficient with it)

Thanks for spotting the BubbleMessageComp delete. I guess if that and DialogWindow had static methods to create them, then that’d be ok because the allocators would be inside the juce library. I’ll see what I can do. Don’t want to force the caller to track them and delete them when they’re not needed though, that’d be a pain.


#16