Rookie question on unique_ptr array


#1

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?


#2

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.


#3

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?


#4

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.


#5

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.


#6

Alright, I’ll change appropriately.


#7

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.