FName - Pass by value or pass by reference

Hi,

My question is simple, should I pass FName by value or by reference ?

  1. I realize that in the engine code, most of the time FName are passed by value. But functions in FName class pass FName by reference.
    As a C++ dev, I have always been told that trivial type (char, int, float, …) should be passed by value but object and struct should be passed by reference.

  2. I did a quick sizeof(myFName) and sizeof(&myFName) and I got respectively 12 bytes and 8 bytes. (Win64 - Shipping config with the case preserving feature).
    FName only contain an union of 1 struct with 3 int32 in it. Sizeof(myInt32) is 4 so it make sense that sizeof(myFName) is 12 bytes.

  3. Even if there is 4 bytes of difference, a reference has an indirection cost. So I’m not sure if it’s a bad trade off.

PS: Please, DO NOT ANSWER : “It depends if you want to modify the argument passed in”, this is not the point here.

Thanks.

Why is that bothering you? :wink:

When passing by const reference you express your intentions - “i just want to look, promise don’t modify”. Engine often uses const FName&.
Non-const refs are other topic -> Open-std

I’m just curious about which one is more efficient, performance wise.
I don’t think that using a const reference solve my issue, but thank you for the link, it was really interesting.

For 1) Why Epic is usually passing FName by copy in the engine code instead of using const reference ?

For 2) Using a const ref doesn’t change the sizes of a FName reference. So my comparison with a FName pass by value is still the same.

For 3) Even if you use a const reference there is still an indirection.

There was quite a lengthy discussion about this a few weeks ago in the UE4 Slackers Discord - the general consensus is that passing by const value is the correct method due to the indirection cost of a reference.

It’s also worth pointing out that FName size actually changes depending on the build type you are using. In Editor they are larger, because they are case-sensitive - whereas outside of editor they are case-insensitive. In Editor they are 12 bytes, but outside of editor they are actually 8 bytes.

1 Like

I think compiler do the work and there is practically no difference in performance.
Im asking because Im sure dealing with FName isnt critical part of your code to worry about performance.

Ad.1) You sure? TotalCommander counts above 500 files with ‘const FName&’ phrase (just in /runtime subdir)
Ad.2) Yes, but const is important part of language. Optimizers loves const :slight_smile:

Seriously? Discussion about eight-byte structure, which perfectly fits in x64 registers? Lol.

Just the messenger. I won’t pretend I understood the full discussion because UE4 Slakcers is full of plenty of smarter people than me - but that was the consensus. It’s not about the size it’s about the indirection cost. A reference is still a lookup to some other location in memory, which could potentially mean a lot of hopping around. I’m sure the difference is practically negligible.

Most routinely-used engine functions use const value (const FName Value) - such as for bone names in animation, body names for physics, attach locations, data table lookups etc. This is all stuff that is used in high volumes at runtime. If in doubt, follow what the engine does. At the end of the day, I seriously doubt any of this really makes a difference to the average game.

It’s not that complicated.
You will see pass-by-value when the engine is dealing with multi threaded data, like animations. When it’s a self-contained function usually it’s a simple const ref.

@TheJamsh no offence. I’m not an expert, but it just seems pretty funny to me.
Core classes like UObject, AActor, etc. are bloated, engine heavily use polymorphism and virtual calls, which destroys cache and branch-prediciton… and people are debating whether to send int64 by value or by reference. Hilarious :slight_smile:

1 Like

Something to add since this thread comes up often in searches:

When exposing functions to BPs (with BlueprintCallable) that use FNames (probably other types too), passing by reference const FName& Name as apposed to FName Name does not allow inputting values in an “input field” on the blueprint node – unless I’ve missed a UPARAM setting somewhere – which for me was a determining factor.

You didn’t miss a UPARAM option. But there is a UFUNCTION meta option: AutoCreateRefTerm=“XXX,YYY, …”.

It’s a little silly for this particular case, but is much more useful with containers where you want a reference but you also want to allow it to be an optional parameter.

1 Like