Juce::vector ? | juce container vs std container

Hello,

i’ve been using c++ for quite a while now and whenever i can i tend to just use a vector, they really suit my way of thinking. juce::vector doesnt exist, will this be available anytime soon? is there any reasy why there is a juce::array insted of simply using std::array? can i just use std::vector for my code or will this hinder stability (does this destroy the leagace detection, i really like this :smile: )

thanks

First of all, choosing std or juce containers should both be safe in terms of stability.

But as you mentioned both, std::vector and std::array I think we have to differentiate between dynamic containers using heap memory and static containers using stack memory.

Dynamic containers can modify their size at runtime. A dynamic container is basically just some metadata like a size and a pointer to some memory. If you tell it to change the size, it will automatically allocate some heap memory, take care to copy the content it already holds over to that new location, safely delete the old chunk of memory and also safely delete its memory on destruction. std::vector and ´juce::Array` are dynamic containers that work like that. The underlying memory management techniques differ a bit and the one might be faster than the other, depending on your use case, but I don’t think that it’s that relevant in a lot of real-world scenarios.

Fixed size containers like std::array work differently. You define its size at compile time and the object will always contain the whole memory internally instead of just a pointer to some external heap memory location.

Both types of containers have their pros and cons. Dynamic containers give you the flexibility of not needing to know the size of the container as a compile time constant. On the other hand, fixed size containers are faster to create and destroy, as they don’t do memory management, they simply increase/decrease your stack pointer which is super fast. Creating temporary dynamic containers during an audio processing routine is a no-go as the allocation performed is a system call with a non-deterministic return time, so here you only want to use fixed size containers as temporarily created objects. The same goes for high performance graphics rendering. But once you set the size on your dynamic container and don’t change it, accessing the data held in it is as fast as accessing data in a fixed size container, so a common practice is to keep dynamic containers as class member, set their size before processing starts and then re-use them without changing their size. Another downside of huge stack based objects like a huge std::array is that stack size is limited – you can create a stack overflow with too big stack objects.

Now if you ask for the availability of juce::vector, what kind of functionality are you looking for that juce::Array doesn’t have?

1 Like

thanks for your explanation! i was aware how memory management works, i just thought there to be a reason why juce::array and juce::ownedarray and so on exist that might expand beyond the obvious

juce::array doesnt seem to be ordered by default (as in i cant “push_back”, i dont want to sort for any number), ill just go for std::vector

This is wrong. juce::Array is a sequential container using continuous storage just like std::vector. The only difference is that the function named push_back in the std::vector is named add in the juce::Array.

Well there is a difference, juce::Array directly holds objects of your desired type while juce::OwnedArray only holds pointers to objects and takes care of deleting them safely. Objects managed in a juce::Array or std::vector need a default constructor and a copy/move constructor. If your type doesn’t satisfy this you have to allocate the objects outside of your container employing whatever non-trivial constructor the object has and just let the container manage the pointer those heap allocated objects.

You can basically exchange

  • std::vector<T> with juce::Array<T>
  • std::vector<std::unique_ptr<T>> with juce::OwnedArray<T>
    without problems besides some slightly different named member functions. It’s just a matter of taste :slight_smile:
2 Likes

I have a container full of containers full of buttons (a step sequencer for dmx lights)

each “fixture” has a remove buttton and there is a “addButton” at the end of the available fixtures, if i just delete stuff it works, when i start adding stuff its getting out of order, .add doesnt add at the end, i just switched my code to std::vector and its working fine

c++ is my native programming language, im used to handling my memory :smile: but i really love the leagace detection, its a sanity check

I’m sorry, but I think the issue must be something different with your code, really. Add does add elements at the end. First of all, the docs say so. Then I used juce::Array multiple times and can simply tell you from my experience that it does. And at last we can have a look at the code:

Array::add calls ArrayBase::add here. After assuring that enough memory is allocated, ArrayBase::add calls ArrayBase:: addAssumingCapacityIsReady here. The implementation of ArrayBase::addAssumingCapacityIsReady looks like this if we only take the overloads taking single elements:

void addAssumingCapacityIsReady (const ElementType& element)   { new (elements + numUsed++) ElementType (element); }
void addAssumingCapacityIsReady (ElementType&& element)        { new (elements + numUsed++) ElementType (std::move (element)); }

We can see that placement new is used to create the object into the desired position in the underlying memory. The location that is chosen is elements + numUsed which is exactly the next memory location after the prior last element. After that numUsed gets incremented by one so that it reflects the current number of used elements again. I don’t see how this shouldn’t work in any case.

I think the great thing especially for people being fluent in C++ is that you can just look up stuff like that easily and just see what’s going on because the juce code base is written super clean. Looking at stdlib sources is often quite a headache compared to this :grimacing:

1 Like

mh, i think you got a point, i never bothered to look closer at the source because we mostly use std at the university, and its a mess :grimacing: so i didnt think of that!

maybe there is something else wrong with my code but im just looking to make it “look kinda allright” becuase i have to finish it by wednesday, if i plan to release my app in the future i will do a full rewrite, its a mess :see_no_evil: