Don’t be fooled. Unreal Engine C++ is not “normal C++”. The unreal header tool enforces strict rules about pointers and the Engine features a Garbage Collector and reference counting under the hood. You might encounter some crashes in shipping builds due to an object being GCed and you tried to access it, but this is usually how far it goes in terms of manual memory management.
Visual Studio
Everything in this Section can easily be resolved by using Rider instead of VS.
- IntelliSense Issues: IntelliSense is not helpful due to extensive use of macros, which are not easily recognized by IntelliSense.
- Visual Assist Dependency: While Visual Assist can help, it's unfortunate that a paid third-party tool is needed for basic functionality in the IDE. (It’s also only “better” than VS, but by far not “good” or even “acceptable”)
- File Reloading: When creating a new C++ class in the engine, it takes about 20 seconds due to recompilation. Visual Studio then needs to reload the solution to recognize the new files, without it code completion often fails, making VS unusable.
- Syntax Highlighting Problems: Initially, Visual Studio highlights everything in red, and Visual Assist may struggle to get the syntax right. Reopening Visual Studio and allowing it to recompute everything is often necessary.
- Override Method Issues: Overriding a method of the parent class is not intuitive. Unlike in C#, pressing ALT + Return does not provide any options. Manual exploration of the parent class or documentation is required to find the method you need.
- Dot vs Arrow Confusion: Sometimes, Visual Studio automatically changes
.
to ->
when you absolutely want a dot, which can be frustrating.
API
- Limited Use of C++ Standard Library: Unreal Engine does not use the C++ standard library (mostly). For instance, many C++14 features have their counterparts in the Unreal library, but with different names (e.g.,
TUniquePtr
) and you should use them instead of the std:: . 🔗
- MoveTemp Function: Unreal Engine’s
MoveTemp
is equivalent to std::move
, but with a different name (ue::move
or ue::Move
would have been more intuitive imho).
- Inconsistencies:
-
Component Handling: The API for handling components is inconsistent:
- Single Component Retrieval: To get a single component, you use a template method like
GetComponentByClass<UStaticMeshComponent>()
.
- Adding Components: Adding components requires a different syntax:
AddComponentByClass(UStaticMeshComponent::StaticClass(), false, FTransform(), false)
, which includes redundant boolean parameters.
- Component Array Retrieval: Retrieving all components of a type uses a different (and deprecated) method:
GetComponentsByClass(UStaticMeshComponent::StaticClass())
, replaced by a more complex method.
-
Converting To/From String:
-
There is a free function ToString
that converts some unreal types to FString
, some others to const TCHAR*
-
There is a FString::FromInt
function
-
There is a FString::SanitizeFloat
function
-
FName
and FText
have a ToString
member function, but only FText
has a FromString
-
EnumToString 🔗 and 🔗
EnumToString<EResourceType>(EResourceType::Wood); // returns: Wood
UEnum::GetValueAsString<EResourceType>(EResourceType::Wood); // returns EResourceType::Wood
StaticEnum<EResourceType>()->GetValueAsString(EResourceType::Wood); // returns: EResourceType::Wood
-
FText
has a EqualTo
function, while FString
calls it Equals
while FName
uses the ==
operator.
-
Inconsistent Logging Mechanisms: Logging to the console and the display uses different mechanisms:
- Console Logging: Done via the
UE_LOG
macro, which includes log levels.
- On-Screen Debug Messages: Logged via
GEngine->AddOnScreenDebugMessage
, which does not support log levels. Additionally, the UE_LOG
macro can be entirely removed by the compiler to save performance, but this is not the case for AddOnScreenDebugMessage
.
- Message Log: While adding errors to the message log works like this: ****
FMessageLog("Log_Category").Error(...)
Unreal Header Tool, Compiling and Debugging
- Unhelpful Error Messages: UHT Error messages are sometimes just bad or even confusing.
- Linker Errors: Due to Unreals custom build tooling the Linker errors often don’t help to find the actually issue. (Missing import? Missing Module Reference? Missing *_API Macro? Missing Function implementation?)
- Namespace Issues: The
UCLASS
and USTRUCT
macros cannot be used within namespaces, limiting the organization of code. 🔗
- Reflection System Compatibility: TOptional<> is not compatible with the reflection system, meaning it can't be used with anything related to Blueprint or UPROPERTY/UFUNCTION. 🔗
- Same for TVariant and a handful other useful types.
- 🗒️ TOptional got DetailsPanel support in 5.4. …. but not Blueprint support.
- Lack of Function Overloading: Unreal Engine does not support function overloading (C++) in Blueprints, even if the display names are different. This limitation forces developers to use different function names for similar functionality, leading to unnecessary complexity.