If you look at the implementation of Array add it is something like this:
void add (const ElementType& newElement)
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
new (data.elements + numUsed++) ElementType (newElement);
The first line is about being able to be thread safe with a CriticalSection, etc. The second line is about allocating in larger blocks. The last line is where the action occurs. It is using a "copy constructor" to add the new item. So it is copying the stack object by reference to the Array.
In concept, this should work fine - and often will, particularly with other Juce classes. The problem is when you start making arrays of your own complex objects. The reason that Juce has a NOCOPY macro is that the default copy operator generated by C++ is pretty dumb. So it is pretty easy to define objects that don't copy correctly.
So if you are going to use Array this way, make sure that your objects have a proper copy constructor and copy operator. An alternate approach would be to used OwnedArray. It is always an array of POINTERS to your objects. So the inside of your loop would be something like:
myOwnedArray.add (new MyComplexObject());
It is RAII, so OwnedArray will take care of delete for you. It is not that Array is bad, but for big and/or complicated objects, OwnedArray will stress the stack less and avoid a lot of copy overhead.