ScopedPointer<> to incomplete type?


#1

Hello fellow JUCErs,

I’m repeatedly running into situations where I want a ScopedPointer<> member to a forward declared type, but this throws compiler errors:

modules/juce_core/memory/juce_ContainerDeletePolicy.h:56:23: Invalid application of ‘sizeof’ to an incomplete type ‘ValueTreeInspectorAttachment’

modules/juce_core/memory/juce_ContainerDeletePolicy.h:58:9: Deleting pointer to incomplete type ‘ValueTreeInspectorAttachment’ may cause undefined behavior

The Current Problem I’m Trying To Solve

(code in outline)

/**
    GuiElement.h
*/

#ifndef GUIELEMENT_H_INCLUDED
#define GUIELEMENT_H_INCLUDED

#include "../../JuceLibraryCode/JuceHeader.h"

// Can't include else we get a circular dependency...
// #include ValueTreeGuiElementAttachemt.h
// ...so we forward declare instead
class ValueTreeGuiElementAttachment;

class GuiElement : public Component
{
public:
    class Listener
    {
        virtual void guiElementChangedState (GuiElement* element) {}
    };
    
    void attach (ValueTree& tree);
    /**
        In the corresponding .cpp file we will include ValueTreeGuiElementAttachemt.h
        and do: attachment = new ValueTreeGuiElementAttachment (tree, *this);
    */
 
private:
    /**
        [THE PROBLEM] Throws compiler errors because ValueTreeGuiElementAttachment
        is an incomplete type
    */
    ScopedPointer<ValueTreeGuiElementAttachment> attachment;
};

#endif  // GUIELEMENT_H_INCLUDED
/**
    ValueTreeGuiElementAttachment.h
*/

#ifndef VALUETREEGUIELEMENTATTACHMENT_H_INCLUDED
#define VALUETREEGUIELEMENTATTACHMENT_H_INCLUDED

#include "../../JuceLibraryCode/JuceHeader.h"

// We have to include GuiElement.h in order to inherit from GuiElement::Listener
#include GuiElement.h

class ValueTreeGuiElementAttachment : public ValueTree::Listener,
                                      public GuiElement::Listener
{
public:
    ValueTreeGuiElementAttachment (ValueTree& tree, GuiElement& element);

    void guiElementChangedState (GuiElement* element) override;
};

#endif  // VALUETREEGUIELEMENTATTACHMENT_H_INCLUDED

##Possible Solutions I Can Think Of

  • Instead of giving GuiElement a private member ScopedPointer<ValueTreeGuiElementAttachment>, give it a ScopedPointer<ValueTreeGuiElementAttachment>*

  • Instead of ScopedPointer, use a raw pointer and call delete on it in ~GuiElement

Any input on how best to approach this problem very much appreciated!


#2

try this…

friend struct ContainerDeletePolicy<ValueTreeGuiElementAttachment>;
ScopedPointer<ValueTreeGuiElementAttachment> attachment;

If I’m completely honest I don’t fully understand why that would work (or not), however if you look throughout the JUCE code this appears to be what Jules is doing to solve this problem.


#3

You haven’t defined a destructor for GuiElement, so the compiler has created one for you, which will contain the destructor of your ScopedPointer member.

BUT when the compiler does this, it does so at the point in your code where the GuiElement class is declared, at which point you’ve not yet declared your ValueTreeGuiElementAttachment class, so it doesn’t know how to delete it.

Easy fix: declare a ~GuiElement() destructor in your header, and define it (it can just be empty) in your CPP file, after the ValueTreeGuiElementAttachment has been properly declared.