How does UE4 C++ use timers via Lambda

To prepare

First, I’ll create a c++ class CppActor that inherits Actor:

Then create BlueprintActor that inherits c++

Drag BlueprintActor into the scene, and THEN I’ll write code in BeginPlay of VS’s appactor.cpp.

First, look at the most common methods used by timers

  1. The first step is to create a FTimerHandle property and a TimerCallback function in the.h file

  1. Step 2 Set a timer in.cpp.

  1. The third step requires specific code to implement the TimerCallback (see figure above).

It’s a lot of steps, and when you have a class with a lot of timers, it can be very bloated, and commands can be a headache

Second, use the Lambda method to use timers

  1. The log shows that the printing sequence is not in the order of ① and ②. Instead, print SetTimer first, and then print the contents of the Lambda. This shows that the delay effect of timer is successful.

How to use external variables in Lambda, how to pass arguments to Lambda, make it follow js, swift… And so on a kind of language similar writing the same function is more perfect.

3. Composition of Lambda

  1. Lambda consists of three parts:
    • [] Capture list: Used to capture variables outside the Lambda.
    • () Argument list: Arguments passed when Lambda is called.
    • {} code block: The part of the concrete implementation code for Lambda.
  2. Specific usage
// Only external values are read
int a = 1;
auto Lambda = [a]() {
    UE_LOG(LogTemp, Log, TEXT("a: %d"), a); ) ; Lambda();// In Log, a: 1
Copy the code
// Read the external value, and +1
int a = 1;
auto Lambda = [a]() {
   a = a + 1;
   UE_LOG(LogTemp, Log, TEXT("in lambda, a: %d"), a);
   };
Lambda();
UE_LOG(LogTemp, Log, TEXT("out lambda, a: %d "), a);
// A compilation problem is displayed with the error: cannot be modified in a non-mutable lambda by copy capture
Copy the code

So the variable Lambda is written:

// Read the external value, and +1
int a = 1;
auto Lambda = [a]() mutable { / / plus the mutable
   a = a + 1;
   UE_LOG(LogTemp, Log, TEXT("in lambda, a: %d"), a);
};
Lambda();
UE_LOG(LogTemp, Log, TEXT("out lambda, a: %d "), a);
A can be assigned to mutable by adding it to mutable.
// But the printed result is:
// in lambda, a: 2
// out lambda, a: 1
// A is indeed assigned inside the lambda
// Does not change the value of a outside the lambda
/ / for js, swift... This can be confusing for language developers, and not as expected.
Copy the code

So what do I have to do to change the value outside of lambda, the value of A

So use reference capture

int a = 1;
int b = 2;
int c = 5;
// Reference capture is preceded by &
auto Lambda = [&a,&b,&c]() {

   b = b + 1;
   c = c + 1;

   a = a + 1;
   UE_LOG(LogTemp, Log, TEXT("in lambda, a: %d"), a);
};
Lambda();
UE_LOG(LogTemp, Log, TEXT("out lambda, a: %d "), a);
// Log
// in lambda, a: 2
// out lambda, a: 2
// At this point, this is exactly what we expected
// ps: 
// [&a,&b,&c] = [&]
// When all variables are captured by reference, it can be shortened to [&]
Copy the code

Now that the expectation of changing the external arguments is complete, the next step is to pass the arguments inside the lambda function

For example, write it like this:

This is how it would be written:

int a = 3;

auto Lambda = [&a]( FString passStr ) {
    // (FString passStr) specifies that an FString argument must be passed when calling the lambda

   a = a + 1;
   UE_LOG(LogTemp, Log, TEXT("in lambda, passStr: %s"), *passStr);
};

FString str = "I am a string from lambda outside";
Lambda(str);

// If Lambda() is used, an error will be reported if no value is passed inside.
// To call a Lambda, you must pass in an FString variable of the same type from the argument list; If the (FString,int,float) argument list has more than one parameter, then you must pass in more than one parameter of the same type.

// If the argument list does not have ().
Lambda() can then be used directly.
Copy the code

Lambda with a return value

// -> int: indicates that the lambda function needs to return an int
auto addOne = [](int a) -> int {
   return a + 1;// must return an int
};
int sum = addOne(2);// Assign the value returned by lambda to sum
// sum = 3;
Copy the code

If you already have a programming background and your programming language has blocks, closures, callbacks… You should be thinking something like this:

At this point in your mind, pass true to the InbLoop parameter when using a timer so that the timer can loop through a Lambda, and when certain conditions are met, call ClearTimer to end the loop.

So we’re going to say, “Experiment is the only criterion for testing truth.”

Run the result:

And we found that it didn’t go 6,7,8 and clear the timer as we expected

We comment out the judgment statement directly

It also doesn’t clear up the Timer, so it keeps repeating

So where the hell are Timer and “A”?


Most languages have no or weakened Pointers, no stacks and heaps. If it is other language developers, will be preconceived, misguided.

There is only one truth:

FTimerHandle Timer;
int a = 6;

// The variables are stored on the stack
// These variables will be released when the function in which they are located is finished, i.e. after}
// Then the reference captured in the lambda points to the value that was released, that is, the value that does not exist.
Copy the code

In c++, values should be stored in the heap, and if they are not released actively, they will be there forever, even if the function runs to}after

The final results of the run were indeed as expected

FTimerHandle * Timer = new FTimerHandle();
int * a = new int(6);
// Using new stores the value permanently in the heap
// Use *a, *Timer to get this value from the heap
// The value in the heap will not be automatically released. Delete A is called, and delete Timer is automatically released

// But objects in UE4 inherit from UObject, they all have CG, and we don't need to call delete.


[this,Timer,a]
// Why not use &
// Since this, *, is itself a pointer and is itself a reference type, no ampersand is required

[this,Timer,a] [=]
// ???
// Readers can do their own research on the Internet. Explore yourself, knowledge can be internalized into their own things.
Copy the code