Reason for unique_ptr instead of member variable?

I was looking at the JUCE examples and noticed heavy use of unique_ptr.

It would really help to know the reason behind this so I can understand the best practices.

For example, line 321 of MenusDemo.h:

std::unique_ptr<MenuBarComponent> menuBar;

Means the addAndMakeVisible code is 2 lines long:

MenuDemo()
{
    menuBar.reset (new MenuBarComponent (this));
    addAndMakeVisible (menuBar.get());
    // ...
}

Why is this preferred over a member variable:

MenuBarComponent menuBar;

And the following code to add the element:

MenusDemo(): menuBar(this)
{
    addAndMakeVisible (menuBar);
    // ...
}

To me this seems shorter and more readable, so I was wondering why unique_ptr was chosen.

I’m not too familiar with that tutorial, but it seems the reason the unique_ptr is used is because it takes this in it’s constructor. Objects that are not default constructible can be allocated on the stack and initialised in the parent class’s member initialiser list, as you demonstrated.

However, IIRC, this is not guaranteed to be fully constructed in the member initialise list, whereas it is guaranteed to be fully constructed in the constructor. Therefore, menuBar needs to be dynamically allocated with a unique_ptr so it can still take this in its constructor, but safely.

2 Likes

You can safely use this in the constructor unless you are using virtual functions. They could end up using the wrong override. IIRC that is undefined behaviour (it could not be defined in the base class at all).
Since we don’t know what the MenuBarComponent does with the this pointer it might be a good idea to stick to @ImJimmis advice not to use it in the constructor (but N.B. if you call std::make_unique in the constructor the same will happen).

Most times you use the unique_ptr if it is something that doesn’t need to exist during the whole lifetime, something that should be changeable during the owners lifetime or to use polymorphic classes (which somehow involves the former).

1 Like

I was just thinking about this same question the other day, when looking at the code for the AudioPluginHost project included in JUCE. In short, using a pointer is useful if a class might need that object – i.e. if it is only conditionally created. As @daniels mentions, this could be time-based, where that object only needs to exist for part of the class’s lifetime.

It could also be configuration-based. If you take a look in the AudioDeviceSelectorComponent constructor, you can see how a bunch of unique_ptrs are only reset if their corresponding arguments in the constructor were true.

And then, in AudioDeviceSelectorComponent::resized(), the Component’s layout can be dynamically built, making room for each sub-component only if it is not equal to nullptr.

1 Like

You can use std::unique_ptr for pimpl idiom and/or to limit dependencies between headers.
To be used as a member the object must be fully defined/visible/complete.
It doesn’t have to be with std::unique_ptr.
In your example it probably doesn’t matter (but with bigger project it quickly be).

Note that personnaly i would write:

MenuDemo() : menuBar (std::make_unique<MenuBarComponent> (this))
{
    addAndMakeVisible (menuBar.get());
    // ...
}
1 Like

IMHO the author of this tutorial has incorrectly chosen inheritance over composition here.

The C++ Core Guidelines specifically state “Don’t call virtual functions in constructors and destructors”. When this is passed to menuBar, some virtual methods of juce::MenuBarModel (which this is being cast down to) are called.

Instead of having the MenusDemo inherit from juce::MenuBarModel, a separate class should be created called DemoMenuBarModel (or similar) which overrides the necessary functionality of the model. An instance of this can then be created before menuBar and simply passed to menuBar's constructor. No need for dynamic allocation, can properly follow the advice of the core guidelines, better adhere to the single-responsibility-principle, and makes the demo simpler.

Just my 2 cents.

1 Like

This is not a problem here though -the guideline is about calling virtual functions of the base class in its own constructor. Here it’s the constructor of a different class called from the derived class constructor, so the object is complete already. I agree it would be cleaner to have menuBarModel as a member -it may not matter much in this case, but it’s bad example. In any case, there doesn’t seem to be a reason to have menuBar on the heap, as it’s not used polymorphically.

3 Likes

Ahh I see, so even though virtual methods of MenusDemo are being called during its construction, its safe since the methods aren’t called by the object itself?

1 Like

It’s safe because it’s effectively a final class. The real issue would be if the constructor of MenuBarModel called its own virtual functions in its constructor -that’s undefined behaviour, because bases are constructed first, in the order they’re declared, and then subobjects. When the MenuBarModel object is constructed, the MenusDemo subobject doesn’t exist yet -the function may be called virtually, but it would work on an incomplete object.

3 Likes

components are not supposed so be copyable, but if you want to construct and destruct certain components on the fly only when they are actually needed you can do that with unique_ptr. i personally find this useful for settings-menus for example. they don’t have to exist all the time and they are also not performance-critical

2 Likes

For only this purpose you don’t need the heap, “placement new” class wrappers achieve the same, e.g. std::variant/std::optional.

1 Like