【问题标题】:RemoveAt from StructArray Ue4从 StructArray Ue4 中移除At
【发布时间】:2017-10-23 11:45:09
【问题描述】:

我在从结构的 TArray 中删除结构时遇到了一些困难。我的结构包含 AudioComponent 和 float。我使用的是 Array.RemoveAt(index),但我从中得到的只是删除了我的结构的一半,即 AudioComponent . 这是为什么?我的功能删除元素如下所示:

void RemoveArrayElement( UAudioComponent AudioComponent )
{
    for( int i=0; i<Array.Num(); i++ )
    {
        if( AudioComponent == Array[i].AudioComponent )
        {
            Array.RemoveAt( i );
        }
    }
}

我想要实现的是完全删除索引,AudioComponent 与它的浮动。

【问题讨论】:

  • “删除我的结构的一半”是什么意思?我不明白你如何删除一个结构的一半或它如何表现出来(或者你如何看待它)
  • 假设 Array[0]=Stuct(AudioComponent0,float0)。使用 Array.RemoveAt(0) 后,我得到的是 Array[0]=Stuct(some invalid value,float0)。
  • 所以数组的大小没有改变,Array 中的剩余元素没有“向前移动”?
  • 您不应按值存储或复制 UObject。而是使用指针 (`UAudioComponent*) 和 UPOPERTY 来防止它们被垃圾收集器破坏。阅读更多:docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/…
  • 看起来元素本身仍然存在,因为即使不再有 AudioComponent,结构的一个参数仍然有效且可访问。而且你的数组在之后没有改变它的大小

标签: c++ arrays unreal-engine4


【解决方案1】:

首先请记住,比较两个对象并不一定会导致预期的相等结果。使用 == 运算符意味着执行一个指定应该发生什么的函数 (bool operator==(L, R);)。因此,如果您没有重载 == 运算符,那么除非您查看定义它的源代码,否则您不知道使用它会导致什么。由于您要删除确切的音频组件而不是看起来相同的实例,因此您希望在数组中使用指针。这也有助于提高性能,因为您在调用 RemoveArrayElement(...); 时并没有复制整个组件,而是一个指针。此外,当数组中存储了两个相同的音频组件并且它们位于索引 a 和 a+1 处时,则删除索引 a 处的音频组件,下一次迭代将跳过您的第二个音频组件,因为所有上索引都减一。

【讨论】:

    【解决方案2】:

    您的代码几乎没有问题。正如其他人在 cmets 中提到的那样,您应该使用指针。如果我没记错的话,你不能使用这样的结构:

    UPROPERTY()
        TArray<UAudioComponent> invalidArray;
    

    您应该使用 UPROPERTY 宏,否则您的属性可能并且很可能会被垃圾收集。 UPROPERTY wiki

    接下来的事情是你正在改变你正在迭代的数组。我写了几个方法,我们来看看:

    void RemoveArrayElement(UAudioComponent* AudioComponent)
    {
        TArray<UAudioComponent*> audioArray; // array will be initialized somewhere else, this is for demo purpose.
    
    
        // you always should check your pointers for validity
        if (!AudioComponent || !AudioComponent->IsValidLowLevel() || AudioComponent->IsPendingKill())
            return;
    
    
        // Correct approach 1 (multiple):
        TQueue<UAudioComponent*> toDelete;
    
        for (int i = 0; i < audioArray.Num(); i++)
        {
            auto item = audioArray[i];
            if (AudioComponent == item || true) // we simulate another condition for multiselect
            {
                toDelete.Enqueue(item);
            }
        }
    
        // better approach for iteration:
        for (auto item : audioArray)
            if (item == AudioComponent || true) // we simulate another condition for multiselect
                toDelete.Enqueue(item);
    
    
        // finalize deletion in approach 1
        UAudioComponent* deleteItem;
        while (toDelete.Dequeue(deleteItem))
            audioArray.Remove(deleteItem);
    
    
    
    
        // almost correct approach 2 (single) :
        UAudioComponent* foundItem;
    
        for (auto item : audioArray)
            if (item == AudioComponent)
            {
                foundItem = item;
                break;          // we can skip rest - but we must be sure, that items were added to collection using AddUnique(...)
            }
    
        if (foundItem)
            audioArray.Remove(foundItem);
    
    
        // correct and the best - approach 3 (single)
    
        audioArray.Remove(AudioComponent);
    }
    

    【讨论】:

    • 我引用了您的 wiki 链接:“非 UPROPERTY 变量不会被 GC 系统计算在内。”。因此,如果不是 UPROPERTY,则不会对任何内容进行垃圾收集。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2019-05-20
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 2021-01-24
    相关资源
    最近更新 更多