How to properly addTab for a TabbedComponent using unique_ptr

Hi,

I want to avoid doing this

AppSettingsComponent *dsc;

dsc = new AppSettingsComponent();
tabbedComponent->addTab("Settings", a_color, dsc, true);

delete dsc

It seems this is old-fashion and will cause a memory leak.

what I tried is to use

auto dsc = make_unique<AppSettingsComponent>();
tabbedComponent->addTab("Settings", a_color, dsc.get(), true);

But this won’t display the dsc tab. However, the tab is displayed correctly with the pointer declared with “new”.

Now I am confused…

TabbedComponent does not at the moment support unique_ptr directly. You have to pass a raw pointer into addTab. There’s an argument to tell if you want the pointed to object be deleted by the TabbedComponent or not. The code you posted where you have a local unique_ptr in a function won’t work.

Thanks, it must be this one

bool deleteComponentWhenNotNeeded ,

If I set it to true, do I still need to delete the pointer explicity using

delete dsc;

No you don’t. deleteComponentWhenNotNeeded is the juce way to say: take ownership.

Best practice is to use your unique_ptr and use .release() instead of .get(), which invalidates the unique_ptr and transfers ownership.

But, is there really any point in using the local unique_ptr then, to begin with? (Juce doesn’t really work that well with any possible C++ exceptions anyway, if that would be the “point” of using the unique_ptr.)

That would have been one argument.
Another would be consistency.
A technical reason in the assembly? Not that I know of, except of exceptions (no pun intended)

.release() works as well.

But should I use it rather “new” pointer? I don’t understand the discussion. What are the exceptions and consistency problems here?

TL;DR: in this particular case it probably doesn’t matter too much.

Using the unique_ptr has an advantage, if you return early from the function, e.g. by an exception, or later accidently adding a return statement before transfering ownership.

As example:

{
    auto* dsc = new AppSettingsComponent();
    // if something happens here like:
    return;
    // or an exception:
    throw();

    tabbedComponent->addTab("Settings", a_color, dsc, true);
}

the raw pointer is destroyed, but not what it points to. It is leaking.

If you do instead:

{
    auto dsc = std::make_unique<AppSettingsComponent>();
    // if something happens here like:
    return;
    // or an exception:
    throw();

    tabbedComponent->addTab("Settings", a_color, dsc.release(), true);
}

when unwinding the stack, the unique_ptr is deleted and it deletes the pointee, i.e. the AppSettingsComponent from the heap.

If there is no return added and no exception can happen, the benefit is just to start getting used to never write new again.