Make visible and resize an array of components

Hi folks! First topic here :upside_down_face:
I would like to make visible a set of components stored in a juce::OwnedArray. I tried to iterate inside the array and make visible each component, even in the resize() method. But when I run the app, components are not visible and when I try to risize it complains: Exception thrown at 0x00007FF940F55D78 (msctf.dll) in ComposerController.exe: 0xC0000005: Access violation executing location 0x00007FF940F55D78.

Here the code:
MainComponent.h

#include "components/Fader.h"
...
public:
    juce::OwnedArray<Fader> faders;
...

MainComponent.cpp

MainComponent::MainComponent()
{
    setSize(1024, 768);
    // Create a fader component and add it in the array
    Fader fader("cc11");
    fader.tabId = 1;
    fader.ccNumber = 11;
    fader.ccValue = 50;
    faders.add(&fader);
    
    // make visible all the faders in the array
    for (Fader * f : faders) {
        addAndMakeVisible(f);
    }
}

// set bounds for all faders in the array
void MainComponent::resized()
{
    for (Fader * f : faders) {
        f->setBounds(20, 90, 200, 300);
    }      
}

Can you help me?
thanks! :wink:

You are adding stack allocated Faders into the OwnedArray, which is not going to work. You need to instead heap allocate the faders and put those pointers into the OwnedArray.

You need to do something like :

Fader* fader = new Fader("cc11");
fader->tabId = 1;
fader->ccNumber = 11;
fader->ccValue = 50;
faders.add(fader);

You will also want to move the setSize call in the constructor from the beginning into the end.

Thanks it works! :partying_face:
Can I do it with smart pointers instead of manually creating the object?

Yes, you could do it with std::unique_ptrs but that seems to me a bit redundant, since the object ownership would be immediately transferred from the unique_ptr to the OwnedArray.

edit : Anyway, for completeness, the way to do it with unique_ptrs :

auto fader = std::make_unique<Fader>("cc11");
fader->tabId = etc...
faders.add(std::move(fader));
1 Like

Maybe instead of using OwnedArray is it better using a vector of unique_ptr?

1 Like

That would be more “modern style”, but wouldn’t really change much how it all works.

// here "faders" would be std::vector<std::unique_ptr<Fader>> faders;
auto fader = std::make_unique<Fader>("cc11");
fader->tabId = etc...
faders.push_back(std::move(fader));
1 Like

yes, it works with both unique as well as shared_ptr. (haven’t tried weak_ptr)

i’m telling you that because sometimes you might get into situations where while a certain vector of components might conceptually be the owners of those components you want to have another pointer to it somewhere else. alternatively you could reference or point to a unique_ptr and get the same effect, but that essentially makes it “not unique anymore” which might feel code-aesthetically unpleasant

I would advise against using shared_ptr unless you’re 100% sure you need a shared ownership model. The fact that you use the term “reference” is a pretty good hint that your ownership model is not shared.

Having a unique_ptr<T> that is referenced elsewhere as a T* (or WeakReference<T> if there is potential for dangling) is a perfectly valid approach, and is much easier to reason about than the same solution using shared_ptr all over the place.

1 Like

aight. don’t wanna argue about that in detail, but just wanted to point out that smart pointers are generally usable in this scenario but with slightly different approaches in mind for basically the same outcome

I’ve now managed for many years without almost ever using std::shared_ptr. Using that is really a minefield that isn’t obvious at first but can hit you in the wrong spot at the worst possible moment. There are some exceptional circumstances where shared_ptr may be required, but those are very rare.

1 Like

i had no obvious problems with shared_ptr yet and everytime someone discusses that with me it seems that the only argument is that shared ownership is bad, but i don’t find that very significant, because even when using shared_ptr there is always a main place for the object and some 2ndary places that will be destroyed before the main place later. especially in components that is a clear hierarchy. the advantage of shared_ptr is you can send them around by copy but the underlying obj will still be the same so you can’t accidently copy that obj and don’t need to specify references all the time