Segfault in Edit destructor when quitting on macOS

I have a demo app consisting of these 3 classes. When I quit (on macos), it ends with a segfault: Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) that I’ve traced to the Edit destructor, specifically Selectable::notifyListenersOfDeletion line 177: updateTimerInstance->remove (this);, although if I remove the call to notifyListenersOfDeletion, it occurs elsewhere in the Edit destructor. I’m not sure what I’m doing wrong that keeps the destructor from destructing properly. I uploaded this project here in case anyone wants to run it: segfault-example.zip - Google Drive

MainComponent initializes an instance of this class:

#pragma once

#include "Clip.h"

namespace phenotype
{
    class Sequencer
    {
    public:
        Sequencer() = default;
        ~Sequencer() = default;

        Clip clip{};
    };
}

Which initializes an instance of:

#pragma once

#include "ServiceRegistry.h"

namespace phenotype
{
    class Clip
    {
    public:
        explicit Clip()
                :edit(ServiceRegistry::getInstance().getClipEdit())
        {
        }

        ~Clip() = default;

        te::Edit& edit;
    };
}

Through this singleton:

#pragma once

#include "JuceHeader.h"

namespace phenotype
{
    namespace te = tracktion_engine;

    class ServiceRegistry
    {
    public:
        ServiceRegistry() = default;

        static ServiceRegistry& getInstance()
        {
            static ServiceRegistry instance;

            return instance;
        }

        te::Edit& getClipEdit()
        {
            return clipEdit;
        }

    protected:
        te::Engine engine{ ProjectInfo::projectName };
        te::Edit clipEdit{ engine, te::createEmptyEdit(engine), te::Edit::forEditing, nullptr, 0 };
    };
}

Creating your Singleton as a static ServiceRegistry instance; is not a good idea since order of destruction is undefined. JUCE has already torn down all it’s classes and when the Edit destructor tries to run, the require JUCE objects no longer exist.

You should design your singleton in a way they you can delete it in JUCEApplication::shutdown or better yet, don’t use a singleton.

Thank you @Roland1, I was able to get it working and eliminate the crash by making sure things are destroyed properly and in the right order in shutdown() and using the juce::Singleton class. What would you recommend instead of a singleton for a standalone app registry for hardware i/o services? I looked into using static classes though couldn’t quite get it to work and it doesn’t seem that different from a singleton. Same with a service locator. Are there some standard juce classes or other c++ packages to handle this?

Instead of a singleton, I usually try to just create one instance of a class, and then any other objects that need to know about it, I pass them a reference. So your MainComponent would look like this:

ServiceRegistry serviceRegistry;
Sequencer sequencer { serviceRegistry };

the sequencer would pass the reference up to clip.

So basically injecting the service registry in as a single dependency. I originally was trying to inject all the services and everything everywhere but this seems like a good compromise and gets rid of the singleton. I’ve rewritten it that way now. I appreciate the tip.