JUCE's interpolators don't work with containers

JUCE’s interpolator classes like CatmullRomInterpolator are stateful. Therefore, if I want to use them on multi-channel signals, I need to construct one instance per channel.

In general, the number of audio channels is variable. Therefore, it is useful to have a std::vector of such interpolators, so I can resize it depending on how many channels I want to process.

However, they are declared JUCE_NON_COPYABLE, which renders them not only non-copyable, but also non-noexcept-moveable. This latter property means I cannot put them into a std::vector. I can only put them into a std::array with a fixed size equal to the maximum number of channels I ever want to process. This is wasting memory.

Would you consider making them at least noexcept-moveable, if they have to be non-copyable? Or otherwise, what pattern would you recommend for allocating per-channel JUCE objects in a scenario where the number of channels is dynamic?

Cheers

How about a vector of unique_ptr?

This would work, but it should not be necessary to allocate these objects on the heap. That’s even worse than the version that takes up more memory because it will be slower (cache misses).

Good point - I can’t really see why they shouldn’t be copyable and moveable, TBH, they’re very simple objects.

Maybe the original decision was made to stop people accidentally passing them around and copying state without really understanding the implications of that, but looking at them now I think probably just making them copyable makes the most sense.

You can still prevent people from accidentally copying state by making them non-copyable, but giving them a noexcept move constructor and noexcept move assignment operator.

1 Like

Another workaround is to use a std::deque which doesn’t have the MoveInsertable requirement.

3 Likes

Excellent, thanks!