Add and remove children or ClearChildren off of a CommonWidgetCarousel, notice how Destruct is not called on the child widgets. And if you’re using a CommonActivatableWidget, OnDeactivated doesn’t get called either. I tested using BP with a CommonWidgetCarousel, added several instances of a BP object with breakpoints set on event node for Construct and Destruct. Construct was reliably called, Destruct was not.
If you look at the CachedSlotWidgets variable you’ll notice it’s only cleared in ReleaseSlateResources. It never releases the children slot content. And if for some reason RebuildWidget is called it only ever continues adding to CachedSlotWidgets, never freeing the old data.
Note, this bug has been around since at least UE 4.27 when I first notice it being added, and looking at UE 5.6 the bug appears to still be there. Also it’s not a permanent leak as long as the Carousel parent is eventually deleted, everything will get cleaned up then; if there’s a long running carousel that’s being added/removed from in production that would be a problem.
This might not cover all cases, but at least adding this change helps fix it for me: (see below code sample).
I also updated `ClearChildren()` to include `CachedSlotWidgets.Empty()` just in case `RemoveChildAt(…)` didn’t address everything. And I updated `RebuildWidget()` to maintain a function local temp copy of `CachedSlotWidgets` before emptying and rebuilding `CachedSlotWidgets` in case stale data accidentally got left in.
When you guys look at the current use of CachedSlotWidgets in CommonWidgetCarousel, unless I’m missing something, it does stand out as an issue to you too right?
`// CommonWidgetCarousel.h:
protected:
virtual void OnSlotRemoved(UPanelSlot* InSlot) override;
// CommonWidgetCarousel.cpp:
void UCommonWidgetCarousel::OnSlotRemoved(UPanelSlot* InSlot)
{
if (InSlot == nullptr)
{
return;
}
if (InSlot->Content != nullptr)
{
const TSharedPtr SafeWidget = InSlot->Content->GetCachedWidget();
if (SafeWidget.IsValid())
{
CachedSlotWidgets.Remove(SafeWidget.ToSharedRef());
}
}
}`