Problem Getting Processor Reference from Struct methods

Hi all,

I trying to make a simple GUI using tabbed panes. I’ve made a struct containing some Sliders and added to a specific tab. This works fine but i’m confused as to reference the processor from the action listener when a slider is modified.

Header File:

class GuiWorkAudioProcessorEditor  : public AudioProcessorEditor, 
								     private Slider::Listener

{

public:
  GuiWorkAudioProcessorEditor (GuiWorkAudioProcessor&);
~GuiWorkAudioProcessorEditor();

//==============================================================================
void paint (Graphics&) override;
void resized() override;

private:

void sliderValueChanged(Slider * slider) override;

// This reference is provided as a quick way for your editor to
// access the processor object that created it.
GuiWorkAudioProcessor& processor;
TabbedComponent tab;
Slider midiVolume;
Slider altSlider;

struct SliderHolder : public Component , private Slider::Listener
{
	
	SliderHolder()
	{		
		addAndMakeVisible(slider1);
	    addAndMakeVisible(slider2);
		slider1.setName("slider1");
		slider2.setName("slider2");
		slider1.addListener(this);
		slider2.addListener(this);
	}

	void sliderValueChanged(Slider * slider) override;

	void resized() override
	{
		
		slider1.setBounds(30, 50,200, 40);		
		slider2.centreWithSize(100, 100);
	}
	
	Slider slider1;
	Slider slider2;

};

In the .cpp file when i try get some info from the processing thread i get this error msg:
“a nonstatic member reference must be relative to a specific object”

CPP File:

void GuiWorkAudioProcessorEditor::SliderHolder::sliderValueChanged(Slider * slider)
{

    if (slider->getName() == "slider1")
    {
	     processor.getSampleRate(); //gives error
    }
    else if (slider->getName() == "slider2")
    {

    }


}

Any ideas of how to solve this or why it’s throwing this error?

It doesn’t matter that your SliderHolder is a class declared within the GuiWorkAudioProcessorEditor class. You still need to explicitly pass a pointer or reference of the processor into the SliderHolder instances. (Like is done with the GuiWorkAudioProcessorEditor where it takes and stores a reference of the GuiWorkAudioProcessor.)

Hi thank you for the swift reply. So is it as simple as declaring:

 GuiWorkAudioProcessor processingRef;

in the struct ? I have tested this and it seems to work but i’m kind of unsure as to why…The way you phrased it, it seemed i would have to pass a reference of the original Processing reference (that is “processor”) to the struct? This stuff is quite confusing for me so any help is always appreciated! :slight_smile:

No, that’s not going to work. The processor must be a pointer or reference in the SliderHolder, not a whole new instance of the processor. (If it actually does work at the moment during runtime, I suspect there’s some additional error in your code that makes the processor instances not be real distinct instances.)

GuiWorkAudioProcessor processingRef; // New instance that’s not going to do you any good in the SliderHolder.
GuiWorkAudioProcessor& processingRef; // Reference
GuiWorkAudioProcessor* processingRef; // Pointer

Hmm i did originally try just declaring a refernce to the processor but it gave me an access error … i will continue working on it tomorrow morning , maybe I’m doing something silly. The code is using a simple Juce GUI tutorial as its base so i think the rest of the code is ok.

Thank you for the help !

Okay so here’s what i came up with…
Struct Header:

	struct SliderHolder : public Component , private Slider::Listener
{
	
	SliderHolder(GuiWorkAudioProcessor &p)
	{		
		processingRef = &p;
		addAndMakeVisible(slider1);
	    addAndMakeVisible(slider2);
		slider1.setName("slider1");
		slider2.setName("slider2");
		slider1.addListener(this);
		slider2.addListener(this);
	}

	void sliderValueChanged(Slider * slider) override;

	
	void resized() override
	{
		
		slider1.setBounds(30, 50,200, 40);		
		slider2.centreWithSize(100, 100);
	}
	
	Slider slider1;
	Slider slider2;
    GuiWorkAudioProcessor *processingRef;
	

};

In the .cpp file the processor address is sent via struct constructor:

tab.addTab("Tab 0", Colours::antiquewhite, new SliderHolder(processor)  , true);

I can then access the processors methods via:

void GuiWorkAudioProcessorEditor::SliderHolder::sliderValueChanged(Slider * slider)
{

if (slider->getName() == "slider1")
{
	float i = processingRef->getStuff();
	 i++;
}

This seems to work ok… but i’m concerned that i may be over complicating things, and don’t want to continue if the code at this stage is not proper. I could not for the life of me figure out how to do this with just Declaring a new reference to the processor such as “GuiWorkAudioProcessor &processingRef;” … So many errors popped up when i try to initialize this variable in the struct constructor…

Any suggestions on this would be most helpful :slight_smile:

A reference class member needs to be initialized in the constructor initializer list. You can’t do = etc in the constructor body itself.

SliderHolder(GuiWorkAudioProcessor &p) : processingRef(p)
{ // constructor body

Having to do the reference initing in the constructor initializer list sometimes makes things tricky, so depending on the situation just using a pointer can be easier to deal with.

1 Like

Ah thanks for reply ! just tried that there and it works perfectly.
So is the way i have gone about it using a pointer also just as valid ?

Just as valid, but using pointers when something will always need a valid object reference in order to work is considered suspicious coding style. (A pointer can easily end up being a null pointer, it’s more difficult to end up with a null reference by mistake.)

Ah ok i see… Thank you so much for your help! Very much appreciated!

BUT a reference is just as fragile as a pointer, if the object it references is freed, you are still doomed! And with references you cannot check for nullptr.

My personal rule of thumb: I use references as back links, like the ProcessorEditor cannot exist without the Processor, hence it is safe to use a reference.

But if the ownership is independent, I use smart pointers like WeakReference, they auto null, if the pointee is deleted and you can just use them with checking for not nullptr.

Let’s not scare people possibly new to all this with all the details… :wink:

Sorry, didn’t mean to. :wink:
It just makes sense to know which one to choose…

I’ve seen people lately assuming, that they are safe if they use a reference… But the problem of dangling pointers is not out of the world…

But I also want to advocate for smart pointers, WeakReference is so useful, and so is ReferenceCountedObject.

And if you want to go STL there is
std::unique_ptr for ScopedPointer
std::shared_ptr for ReferenceCountedObject and
std::weak_ptr for WeakReference (same as Component::SafePointer I guess)

People complain that proper memory management is hard on C++ and that java garbage collection is so handy, and ObjectiveC with ARC is so advanced. But they forget, it is all possible in C++ too nowadays. It is just not mandatory…

So everybody use them and enjoy! :slight_smile:

1 Like