Bug? Feature? It's not expected behavior, that's for sure with Array::fill

        array.ensureStorageAllocated(size);
        array.fill( {} );

You’d think that this would fill the array with whatever type it holds. But it doesn’t. that’s because ensureStorageAllocated doesn’t change numUsed, which is how end() is computed.

    void ensureStorageAllocated (int minNumElements)
    {
        const ScopedLockType lock (getLock());
        values.ensureAllocatedSize (minNumElements);
    }
//Array
    inline ElementType* end() const noexcept
    {
        return values.end();
    }
//ArrayBase
    inline ElementType* end() const noexcept
    {
        return elements + numUsed;
    }

which means that this loop for fill() is never entered:

    /** Fills the Array with the provided value. */
    void fill (const ParameterType& newValue) noexcept
    {
        const ScopedLockType lock (getLock());

        for (auto& e : *this)
            e = newValue;
    }

Any thoughts on why this is designed to not work as expected?

if Array::fill is designed to overwrite existing values, shouldn’t the name be changed?

this is the work-around for anyone who stumbled upon this:

        array.ensureStorageAllocated(size);
        for( int i = 0; i < size; ++i )
        {
            array.add( {} );
        }

or

array.insertMultiple(0, {}, size);

It’s designed as expected: fill() simply overwrite the array over array.size()
you want to call array.resize (numItems) in your case ?
ensureStorageAllocated() does not change the size (number of items) of the array, it only allocates the memory

1 Like

not to be nit-picky, but fill implies that something is empty and will be filled up with something. Array::fill requires the array to already have a bunch of values in it before it can replace all of those values with the specified value.

fill is a bad name for what the function does.

I’m not sure how I missed Array::resize in the docs. thanks for suggesting that :slight_smile:

All STL containers behave like this and it’s the correct, expected behavior.

@reFX Most of them have the resize(num, valueToFillWith) but only std::array<> has fill as an actual member function. and std::array<> allocates the space upon construction so std::array<>::fill() actually fills up the array with whatever value you tell it to fill up with.

Perhaps you’re thinking of std::fill( )? https://en.cppreference.com/w/cpp/algorithm/fill
std::fill() operates on valid iterators.
juce::Array::fill operates on the array itself.

I think a documentation note that said

if the array has had nothing added to it (via .add() or .resize() ), 
this function will do nothing

would be helpful, and also that it

overwrites all existing values in the Array

It’s a subtle difference, but an important one and would have saved me (and probably others) a lot of debugging time if the documentation said those things.
just my 2 cents…

There’s no difference between a member function and a free function in this case, the key here is that ensureStorageAllocated is equivalent to calling reserve on a std::vector.

It’s a misunderstanding of the ensureStorageAllocated function not the fill function surly you expected fill to do nothing if the array was empty? maybe ensureStorageAllocated should be clearer in stating that is does not change the size of the array? It could also have a link to the resize function.

1 Like

no, I expected, after i allocated storage, to fill that storage with values via the fill function.

I don’t think that’s an unreasonable expectation, given the names of the functions…

Exactly you expected the array wasn’t empty after calling ensureStorageAllocated so the documentation for ensureStorageAllocated is surely what needs addressing not fill, although there’s no harm in updating both of course.

I don’t think it’s completely unreasonable but I think it’s equivalent to the following…

array.reserve(size);
std::fill(array.begin(), array.end(), {});
3 Likes