Recursively find first child component of a given class


#1

To keep my code adaptable to class and layout changes I wanted to be able to pull out the first component of a given type. I came up with this recursive method:

    template<class ComponentClass>
    ComponentClass* getChildComponentOfType()
    {
        for (int i = 0; i < getNumChildComponents(); ++i)
        {
            ComponentClass* comp = dynamic_cast<ComponentClass*> (getChildComponent (i));
            if (comp != nullptr)
                return comp;
            else
                return getChildComponentOfType<ComponentClass>();
        }
        return nullptr;
    }

However I’m getting a bad access crash on the following line (juce_Array.h:240):

        const ScopedLockType lock (getLock());

This is after quite a lot of recursions/iterations. I’m wondering if this might be the wrong approach!?


#2

Let’s play “spot the infinite loop”!

This is the kind of mistake that would surely be easy to spot if you step through it in your debugger…?


#3

i guess you are calling local getChildComponentOfType<ComponentClass>() inside your local template itself over and over, no ? it wont go recusively here, unless your ColponentClass is valid pointer, then you can invoke your recursion with it.
or im tripping ?


#4

Yes I’ve realised my mistake here!! Had a bit of a “doh” moment… Need to pass in the parent component to actually drill down into the component tree. Will post my solution shortly!


#5

i wish my doh’s would make me money, i would be rich as hell then


#6

Working solution:

    template<class ComponentClass>
    static ComponentClass* getChildComponentOfClass(Component* parent)
    {
        for (int i = 0; i < parent->getNumChildComponents(); ++i)
        {
            Component* childComp = parent->getChildComponent(i);
            ComponentClass* compOfDesiredClass = dynamic_cast<ComponentClass*> (childComp);

            if (compOfDesiredClass != nullptr)
                return compOfDesiredClass;
            else
            {
                ComponentClass* nextChild = getChildComponentOfClass<ComponentClass> (childComp);
                if (nextChild != nullptr)
                    return nextChild;
            }
        }
        return nullptr;
    }

#7

Or after a code-review… :slight_smile:

template<class ComponentClass>
static ComponentClass* getChildComponentOfClass(Component* parent)
{
    for (int i = 0; i < parent->getNumChildComponents(); ++i)
    {
        auto* childComp = parent->getChildComponent(i);

        if (auto c = dynamic_cast<ComponentClass*> (childComp))
            return c;

        if (auto c = getChildComponentOfClass<ComponentClass> (childComp))
            return c;
    }

    return nullptr;
}

I wish you’d all get on board with the “no-else-after-return” rule!


#8

Thanks Jules, its been a while since I’ve had any code reviewed, appreciate that :slight_smile:

Any chance this method could make it into the Component class?


#9

+1 for embeding it into [Component]


#10

I’m not super-keen on that. Unlike findParentComponentOfClass, it’s the kind of thing where you’d add it and then people would start wanting more control, e.g. an option to search backwards, or to return an array of all the matches, etc. And it works perfectly well as a free function like this one.


#11

Fair point, I can see how different use cases would warrant different variations.