Leaked object with OwnedArray

I have been using OwnedArray in a few classes of a library:

In a Venue class I have an OwnedArray of Zone.
In the Zone class I have an OwnedArray of Speaker.
In a Spatial class I have an OwnedArray of SoundSource.

I initially create a static Venue object and a static Spatial object, and have a pointer association between the two.

My program works in Windows/Visual C++ (doing spatial rendering), but in Debug mode on exiting the program, I get:
“Leaked objects detected: 1 instance(s) of class OwnedArray”

On pressing continue, I get:
Detected memory leaks!
Dumping objects →
{2717} normal block at 0x00000186C933D6E0, 52 bytes long.
Data: < =B1 =^q =^q => E6 E7 BE 3D 42 31 FD 3D 5E 71 BD 3D 5E 71 BD 3D

I assumed that once the program ended and the static objects were removed from the stack, the OwnedArrays would take care of deleting their pointed-to objects.

Any ideas of where I might be going wrong?

Your problem is using the static variables for the OwnedArrays. The Juce memory leak detector is itself destroyed before the static variables, so it will see those static variables as “leaked”. The OS will of course ultimately clean up all the memory of the process, but you will probably want to come up with some more clean solution than using those static variables.

1 Like

Thanks for the quick reply!
I don’t use a static variable for the OwnedArray, but rather create a static object of a class that has the OwnedArray, for example:

class Venue
{
public:
juce::OwnedArray zones;
int noZones;
.
.
}

static Venue myVenue;

I will then add zones:

zones.add(new Zone());

where the Zone class contains an OwnedArray of Speaker.

I previously created Venue and Spatial on the heap with:
Venue* pVenue = new Venue;
and deleted them in the destructor of the object where they were created. However, I had the same result - program worked, but leaks happened.

Just can’t see a different way to implement the design!

It’s best to avoid static objects in general.

https://isocpp.org/wiki/faq/ctors#static-init-order

https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use-members

Try using a std::unique_ptr instead, or use one of the methods from the second link.

Matt

Your OwnedArray inside the Venue object is also effectively static, when your Venue object is static.

1 Like

Many thanks for the further help!
That makes sense @xenakios - the owned array would also be static considering its a member of the class of the static object.
@Matt - I have decided to rather go for std::shared_ptr since I want access to the objects via more than one pointer.
So I have now tried:

class Show
{
.
.
public:
std::shared_ptr pSpatial;
std::shared_ptr pVenue;
.
.
}

and in the Show constructor:
pSpatial = std::shared_ptr(new Spatial(noSources));
pVenue = std::shared_ptr(new Venue());

pSpatial->connectToVenue(pVenue);
pVenue->connectToSpatial(pSpatial);

So a simple two way association between objects that are in the heap. However, I still have the program working as expected, and on exit (Debug mode) get 3 of these:

*** Leaked objects detected: 1 instance(s) of class OwnedArray
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
CodaServer.exe has triggered a breakpoint.

Followed by a much larger number of:

Detected memory leaks!
Dumping objects →
{1996587} normal block at 0x0000014440F576E0, 52 bytes long.
Data: < =B1 =^q =^q => E6 E7 BE 3D 42 31 FD 3D 5E 71 BD 3D 5E 71 BD 3D

As previously mention, Venue has an OwnedArray of Zone. Zone has an OwnedArray of Speaker, Spatial has an OwnedArray of SoundSource. At no time do I do a ‘new’ or ‘delete’. So I would assume that the objects within the OwnedArrays would be deleted.

Any further ideas would be much appreciated!

(Didn’t checked your code but) HTH: Leak detector and static variables

Edit: You should well format your code in your posts, since they are very hard to read such that.

@nicolasdanet - thanks, I have moved away from static variables and am using shared_ptrs now, but still problems with instances of OwnedArray that are leaked. Thanks also for the prod regarding code format - will make sure that I do that!

Are you using some global variables now? Those will have the same problem as the statics do, the destruction order may be that the Juce leak detector is destroyed before the globals are, then triggering the leak detector.

@xenakios - thanks for thinking of this. No, I don’t have global variables - all instantiated objects communicating with each other. I do of course get ObjectClass pointers from the OwnedArrays and use the attributes of the objects they point to. I also do store these pointers within objects for later access. I wonder whether this might be an issue?

You can have false positive leaks and true leaks. False postive leaks are usual with static/global objects mixed with JUCE leak detectors. It is a bit disturbing at first. If you don’t have any such static/global objects it means you have a true leak.

Note that static/global objects are instantiated before the start (main function) of the software. They are released after the end of the software. It is not related of how they communicate during the life of your software.

Thanks for the further info - yes, pretty sure its a true leak, but how to find it!!

Is there any way to trace where leaks of OwnedArray objects are coming from? It’s one thing to know that I have 16 OwnedArray instances being leaked, but I need to know who created them. So far, I haven’t been able to find the culprit, and stopping at the leak assertion doesn’t allow me to see anything about whose OwnedArray these instances were. I definitely do not have 16 static objects containing OwnedArrays, and I don’t see in my code any place where there are 16 (always 16, no more, no less) objects which each contain an OwnedArray.

How about HeavyweightLeakedObjectDetector?

https://docs.juce.com/master/classHeavyweightLeakedObjectDetector.html

Matt

1 Like

Nice! Hadn’t seen or heard of that. (Obviously!) Thanks!

The shared_ptrs might be the culprit. If object A holds a shared_ptr of B and B holds a shared_ptr of A they will never be cleaned up.
shared_ptrs are just no magic solution, they need to be handled with caution.
It is better to find a place where the object is owned and pass on a reference to it where it is needed.

Thanks Daniel, they might well be the culprit! What you say, after further reading, makes complete sense. I believe that I need a shared_ptr and weak_ptr relationship to implement an association, and to convert the weak_ptr to a shared_ptr when I need to access the pointed-to object. Really finding my way in this new world of smart pointers! On holiday at present, but will try out and report back next week.

A good talk about: < CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.” - YouTube >.

@nicolasdanet - thank you very much for this link - will be watching it a couple of times!

This was exactly what we needed to solve the problems. Thanks, Matt!