I have a Layer class which contains certain objects like buttons, sliders etc. I've built the Layer class so that it's capable of refreshing itself. Essentially, it deletes all/most of its objects and then recreates them. The reason for that is that I have various functionalities like changing font size or the theme of my UI and I want to have the changes be apparent immediately.
The only way to accomplish this consistently is to simply rebuild everything, because the themes and font sizes affect both the look and the layout of everything. This all works really well and I'm satisfied with the system.
However, issues (and by issues I mean crashes) arise when one the objects that belongs to the layer initiates the refreshing. For instance, I have a font size slider which is supposed to change the font size and then make the layer refresh. It has a callback to the refresh function of the layer, captured by a lambda, and stored in a member std::function object. What happens when the function is executed is that at some point, before the calling function is finished, the slider, of course, gets destroyed and destroys the function along with it. Thus the function that's currently running stops existing and the program crashes.
My question is what would be a good and elegant way of accomplishing this behavior that doesn't result in crashes via this paradoxical situation?
EDIT: Code
class MySlider : public MyNode
{
//... various other class members
std::function<void()> functionOnRelease = nullptr;
MySlider::MySlider(/*constructor arguments*/)
{
this->preferenceKey = key;
slider->addTouchEventListener([=](Ref* sender, ui::Widget::TouchEventType type)
{
if (type == ui::Widget::TouchEventType::ENDED)
on_release();
});
//... remainder of constructor body
}
void MySlider::set_function_on_release(const std::function<void()>& functionOnRelease)
{
this->functionOnRelease = functionOnRelease;
}
void on_release()
{
if (preferenceKey.empty() == false)
PREFM->set_preference(preferenceKey, slider->getPercent() + min);
if (functionOnRelease)
functionOnRelease();
//the program crashes at this point when the slider gets destroyed
}
}
//The layer in question and the function that creates its slider
void Options::create_font_size_slider()
{
NodeVector sliders;
//there's a static create function convention imposed by the engine
auto fontSizeSlider = MySlider::createWithPreferenceAutomatic("Font Size: ", "FontSizePercentage", 50, 150, false, sliders);
fontSizeSlider->set_function_on_release([=] { this->refresh(); /*this kills the slider*/});
}
EDIT 2:
I've managed to avert the crash by a simple and ugly hack. I've forced the refresh() function to happen on a separate thread after a slight delay (0.05 seconds). This gives enough time for everything to happen without the delay being noticeable. I can live with the potential occasional crash in the event of a really slow device and strange thread scheduling since everything that needs to be done gets done before the crash can occur.