How to sort an array of pointers by their name

Why won’t the following code compile:

OriginalArray.Sort([&](USceneComponent* A, USceneComponent* B)
{
    const FString& AName = A->GetName().ToLower();
    const FString& BName = B->GetName().ToLower();    
    return AName.Compare(BName) < 0;
});

This gives the following compilation error:

error C2664: 'bool (__vectorcall *)(USceneComponent *,USceneComponent *)' : cannot convert argument 1 from 'USceneComponent' to 'USceneComponent *'

I don’t see why it is trying to use a dereferenced pointer when the array is an array of pointers and the predicate takes two pointers.

Hello,

Since the defined capture takes members of outside scope by reference, you shouldn’t declare arguments as pointers:

OriginalArray.Sort([&](USceneComponent A, USceneComponent B)

If you like to learn more about lambas in C++, please go here:

http://en.cppreference.com/w/cpp/language/lambda

Hope this helped!

Cheers!

1 Like

I suppose your array element type is [USceneComponent *], so I suggest to do this:

OriginalArray.Sort([&](USceneComponent &A, USceneComponent &B)

{

 const FString& AName = A.GetName().ToLower();

 const FString& BName = B.GetName().ToLower();    

 return AName.Compare(BName) < 0;

}

Build will fail if the parameters have no & ahead of them. This way works for me. It is important to check if all the array elements are not NULL, otherwise, it crashes.

As the others already pointed out, you have to use references instead of pointers. This is due to a weird unreal decission to apply an dereference when sorting arrays of pointers.

This also means, you can never sort arrays which might contain nullptr values, as it will just crash in the attempt to dereference these.

I recomment to avoid .Sort() or .StableSort() for arrays of pointers for that very reason and use Algo::SortBy instead, if possible. The usage is a bit different, instead of a compare function you pass a projection function to a value that needs to have a compare operator, but frankly - that is simpler in almost all of the cases anyway.

For your example, you would do:

Algo::SortBy(OriginalArray, [&](USceneComponent* A)
{
    const FString& AName = A->GetName().ToLower();
    return AName;
});

…and while we are on the subject, I recommend you don’t capture everything “by default”, but instead only capture what you really need - that often avoids accidental errors. In this case, your lambda does not need to catch anything.

Secondly, you might want to check for nullptr, if you aren’t absolutely sure that there can never be nullptr in the array. You know… to avoid crashes…

Finally, you might consider using “GetFName()” instead of “GetName().ToLower()”, which might be a LOT faster.

So my final version would be:

Algo::SortBy(OriginalArray, [](USceneComponent* A)
{
    return A ? A->GetFName() : FName();
});
3 Likes