One problem is modifying the size of an array while iterating over it with a foreach loop is unhealthy. If we were programming in C++ one would say that the splice invalidates the iterator. We don't have such well defined terminology for what you're doing, in Perl. But the effect is similar.
Additionally, even if this did work as you intended, you're doing way too much work. To splice out an element within an array, all elements to the right need to shift leftward one. So each and every splice is a linear operation. And the general algorithm of filtering an array using a loop and splice will have quadratic growth. If you're willing to trade memory for speed, a better solution is one that populates a new array (even if internally) with the elements filtered from the original array. This sort of algorithm has a linear order of growth as the array's size grows.
Not only is this better algorithm an order of magnitude faster, it's also far easier to write, especially since that's what the Perl built-in grep function does just that:
my @array = ( 'stuff', '', 'stuff', '', '10', '', '-', '' );
@array = grep { $_ ne '' } @array;
If you want to remove all elements that have either an empty string, or are not defined, you could just do this:
@array = grep length, @array;
This works because length returns a false value for empty strings, as well as for containers that are 'undef'.
my @array = ( 'stuff', '', 'stuff', '', '10', '', '-', '' );
So on the first iteration
|