How to write this preset Copy/Paste manager without memory leak?

I had to change the way my copy paste manager worked for Juce 7 as the prior version didn’t anymore. At the same time I consolidated my .cpp and .h files into a .h file and I might have butchered the Singleton code.

I am now getting memory leaks upon closing the running program and I’m not sure which of these two changes are triggering it.

The copy/paste manager still works but I obviously don’t want memory leaks. Any ideas? Did I do the Singleton okay? Is the unique_ptr being used wrong? Thanks for any help.

#pragma once

#include "JuceHeader.h"

class CopyPasteManager
{
public:
    CopyPasteManager() {};
    ~CopyPasteManager() {
        DBG("DESTRUCTOR RUN");
        mCopyState.reset(); 
    };
    
    void copy(AudioProcessorValueTreeState* inState) {
        juce::ValueTree state = inState->copyState();
        std::unique_ptr<XmlElement> xmlStateCopy = state.createXml(); //is this a memory leak???
        mCopyState.reset(xmlStateCopy.release());
    }

    
    void paste(AudioProcessorValueTreeState* inState) {
        if (mCopyState->hasTagName(inState->state.getType())) {
            inState->replaceState(ValueTree::fromXml(*mCopyState));
        }
        
    }
    
    juce_DeclareSingleton (CopyPasteManager, false)
    
private:
    
    std::unique_ptr<XmlElement> mCopyState;
};
juce_ImplementSingleton(CopyPasteManager)

I presume I am not handling the unique_ptr in copy properly but have spent an hour trying different things and can’t help that using this function provokes

*** Leaked objects detected: 231 instance(s) of class XmlElement
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
A breakpoint instruction (__debugbreak() statement or a similar call) was executed in SinSynth.exe.

Prior copy code which worked without leaks was as follows, but this is somehow not working in JUCE 7 because state.createXml() now makes another unique_ptr rather than the xml itself:

    auto state = inState->copyState();
    mCopyState.reset(state.createXml());

I appreciate any suggestion to fix it. Thanks again.

The copy method is ok, but can be improved at several points.

Instead of release and reset you can use assignment with std::move():

mCopyState = std::move (xmlStateCopy);

Or if you remove that local variable, you don’t even need to move:

mCopyState = state.createXml();

I think it is the singleton that actually leaks. A singleton is just a safety wrapper around a static variable. But static variables are destroyed after the leak detector in undefined order.
The best option is to inherit your CopyPasteManager from juce::DeletedAtShutdown. This is a cleanup helper, that will delete the singleton safely before the leak detector checks.

Out of curiosity, does the DBG("DESTRUCTOR RUN"); print before or after the leak detector? (hit continue when the leak detector stops)

Thanks @daniel. Looks like there were two changes needed.

Adding the inheritance of DeletedAtShutdown allowed the destructor to run before the leak assertion (wasn’t before).

Then I had to add clearSingletonInstance() to the destructor as well.

The std::move didn’t work but the other method you suggested also does so I have two methods that don’t provoke at least any reported memory leaks:

#pragma once

#include "JuceHeader.h"

class CopyPasteManager : DeletedAtShutdown 
{

public:
    CopyPasteManager() {};
    
    ~CopyPasteManager() {
        DBG("DESTRUCTOR RUN");
        //mCopyState.reset(); 
        clearSingletonInstance();
    };

    void copy(AudioProcessorValueTreeState* inState) {
        juce::ValueTree state = inState->copyState();

        //option 1:
        //std::unique_ptr<XmlElement> xmlStateCopy = state.createXml(); //is this a memory leak???
        //mCopyState.reset(xmlStateCopy.release());
        
        //option 2:
        mCopyState = state.createXml();
    }

    
    void paste(AudioProcessorValueTreeState* inState) {
        if (mCopyState->hasTagName(inState->state.getType())) {
            inState->replaceState(ValueTree::fromXml(*mCopyState));
        }
        
    }
    
    juce_DeclareSingleton (CopyPasteManager, false)
    
private:
    
    std::unique_ptr<XmlElement> mCopyState;
};

juce_ImplementSingleton(CopyPasteManager)