Rookie question on unique_ptr array

This may be a rookie c++ question, but I just want to make sure I handle this correctly.

In my plugin I have an abstract class called LadderFilterBase. I’m instantiating 6 filters, so I can process 3 types of filter for each channel. Like this:

std::unique_ptr<LadderFilterBase> filterA[2], filterB[2], filterC[2];

In the ctor of the AudioProcessor I create a new object for each filter like so:

for(int channel = 0; channel < 2; channel++)
{
    filterA[channel] = std::unique_ptr<LadderFilterBase>( new ImprovedMoog );
    filterB[channel] = std::unique_ptr<LadderFilterBase>( new ThreeFiveModel );
    filterC[channel] = std::unique_ptr<LadderFilterBase>( new DiodeLadderModel );
}

Then, in my processBlock I call following function:

void MonosynthPluginAudioProcessor::applyFilter (AudioBuffer<FloatType>& buffer, 
     std::unique_ptr<LadderFilterBase> filter[],
     ScopedPointer<dsp::Oversampling<FloatType>>& oversamp)
{
   <-- CODE --> 
}

processBlock callback:

// applying filter
if (*filterSelectParam == 0)         { applyFilter(osBuffer, filterA, oversampling) ; }
else if (*filterSelectParam == 1)    { applyFilter(osBuffer, filterB, oversampling) ; }
else                                 { applyFilter(osBuffer, filterC, oversampling) ; }

Is this a proper way of handling these object? I want to make sure that I’m passing the filters by reference for performance sake and want to make sure they’re deleted properly.

Or, is there a better way of instantiating/passing?

Why are you mixing std::unique_ptr and Juce’s ScopedPointer in your code?

Regarding passing the unique_ptrs, if the code compiles and runs without crashing, it’s OK. If the code ended up attempting to copy the unique_ptrs, it wouldn’t compile, as unique_ptr can’t be copied. (But even if it was copied, the cost wouldn’t be that high because the unique_ptrs just wrap a pointer, not the object pointed to.)

You might want reconsider if you really want to be using raw C arrays in your C++ code.

I used to use ScopedPointer for this, but then I read this in the documentation:

Important note: The class is designed to hold a pointer to an object, NOT to an array! It calls delete on its payload, not delete, so do not give it an array to hold! For that kind of purpose, you should be using HeapBlock or Array instead.

As for using raw C arrays, I like the simplicity, but it’s probably not ideal. I could simply do filterA_l, filterA_r etc. But I think that’s not really an elegant solution. Would you suggest an other method?

We’d actively encourage people to use std::unique_ptr in their own code. ScopedPointer was always an interim solution for pre-C++11 compilers, and in the long run std::unique_ptr is a better choice.

1 Like

That thing in the documentation means you should not do something like :

ScopedPointer<MyClass> ptr(new MyClass[10]);

Whereas something like :

ScopedPointer<MyClass> objects[10]; 

Should work, but as was already mentioned by Jules, you might want to aim at using std::unique_ptr when possible.

Alright, I’ll change appropriately.

In your particular use case the raw C arrays can be fine, if you are completely sure there will ever only be 2 array elements. (Raw arrays are problematic because it’s too easy to lose the number of elements the array has when passing the array or a pointer to it into functions etc.)

Using C arrays is a bad habit to get into, since options like std::vector and std::array are also available.