Coding conventions for Unreal Engine 4 for C++, Blueprint and Python
Home / C++
NOTE: These pages are being rewritten as 'live' source code conventions in the form of an Unreal Engine plugin.
See Open Unreal Coding Standard
Do not use any of the functions and types defined in the std namespace!
For all essential functions there are unreal specific substitues including but not limited to:
std namespace | UE4 replacement |
---|---|
static_cast<T>() |
StaticCast<T>() or Cast<T>() for UObjects |
move<T>() |
MoveTemp<T>() |
forward<T>() |
Forward<T>() |
unique_ptr<T> |
UniquePtr<T> |
shared_ptr<T> |
SharedPtr<T> |
weak_ptr<T> |
WeakPtr<T> |
vector<T> |
TArray<T> |
array<T> |
TArray<T, TInlineAllocator<T>> |
map<T, U> |
TMap<T, U> |
tuple<T...> |
TTuple<T...> |
The engine source code also contains a significant amount of type traits that substitute the std type traits.
#if
instead of #ifdef
#undef
as early as possibleUse const
when possible for
Do not use const in the following situations:
// Bad - returning a const array
const TArray<FString> GetSomeArray();
// Fine - returning a reference to a const array
const TArray<FString>& GetSomeArray();
// Bad - returning a const pointer to a const array
const TArray<FString>* const GetSomeArray();
// Fine - returning a pointer to a const array
const TArray<FString>* GetSomeArray();
Source: C++ Core Guidelines F.15:
Stick to the following table when possible and document decisions whenever you pick a different approach:
parameter functionality | Cheap or impossible to copy type (e.g. int , FUnqiuePtr<T> ) |
Cheap to move (e.g. TArray<T> , FString ) or Moderate cost to move (e.g. TArray<TMap<T, U>> , BigPOD ) or Don’t know (e.g. unfamiliar type, template) |
Expensive to move (e.g. BigPOD[] ) |
---|---|---|---|
Out | X f() |
X f() |
f(X&) |
In/Out | f(X&) |
f(X&) |
f(X&) |
In & read only | f(X) |
f(const X&) |
f(const X&) |
In & retain copy | f(X) |
f(const X&) |
f(const X&) |
When you really want to add explicit move semantics support, check if your parameter falls into one of the following cases:
parameter functionality | Cheap or impossible to copy type (e.g. int , FUnqiuePtr<T> ) |
Cheap to move (e.g. TArray<T> , FString ) or Moderate cost to move (e.g. TArray<TMap<T, U>> , BigPOD ) or Don’t know (e.g. unfamiliar type, template) |
Expensive to move (e.g. BigPOD[] ) |
---|---|---|---|
Out | X f() |
X f() |
f(X&) |
In/Out | f(X&) |
f(X&) |
f(X&) |
In & read only | f(X) |
f(const X&) |
f(const X&) |
In & retain copy | f(X) |
f(const X&) + f(X&&) & move |
f(const X&) |
In & move from | f(X&&) |
f(X&&) |
f(X&&) |
= default;
syntax where possibleNot all features of C++11, C++14 etc are supported by all UE4 target platforms. However following features are reccommended to use:
static_assert
use for compile time assertion. Prefer over any runtime checks, especially for templates.override
and final
are strongly encouraged for overriding virtual functionsnullptr
should be used instead of C-style NULL
macro in all cases.
typeof(nullptr)
should be replaced with TYPE_OF_NULLPTR
for templates to ensure compatibility with C++/CX builds (e.g. XBox One)auto
keyword for variable types, lambda types and template return types
TActorRange
instead of TActorIterator
)[&Foo]
instead of automatic capture ([&]
and [=]
)[]() -> bool {return true;}
) to make compiler output more relevant/precise // If you do use plain enums, always wrap them with a "namespace" struct:
struct EFlags
{
enum Type
{
Alpha = 0b001,
Beta = 0b010,
Gamma = 0b100
}
};
enum class EActualEnum
{
Foo = EFlags::Alpha | EFlags::Beta,
Bar = EFlags::Beta | EFlags::Gamma
};
To ensure your module’s header files can be included by other modules, you should stick to these two rules:
./
or ../
notation #include "MyModule/SubFolder/HeaderFile.h"
#include "SubFolder/HeaderFile.h"
Instead of using built-in types like int and short, the UE4 typedefs should be used:
Standard types that may be used:
String and number literals may be used. Do not use raw string literals ("foo"
, L"bar"
), but instead always use the TEXT("foo")
macro to surround string literals, unless they are fed into other macros, such as INVTEXT("My culture invariant")
.
If you need FTexts for UI display, never convert from FString, always write localizable FTexts using LOCTEXT()
, or culture invariants using INVTEXT()
for dev UI that should not be translated:
// localizable button label
FText ButtonLabel = LOCTEXT("ButtonLabel", "Press Me!");
// culture invariant used for DEV UI, so it doesn't end up in loca kits
FText DevButtonLabel = LOCTEXT("DevButtonLabel", "Press Me! (only if you're a dev)");
Never use the LogTemp log category for anything other than temporary debug code. Always use/create an appropriate log cateogry using one of the declare/define log cateogry macros instead (see UE4 Community wiki).