Std::call_once isn't called once

Hi guys!

I’m really stuck here with this problem.

You see, I have a AActor class here where I’m trying to use std::call_once inside the constructor. In the editor, I have created a BP based on this class, and I have placed three instances of it. But when I start the game, the procedure that was given to std::call_once isn’t called once. I tried to do something else, created a macro and used atomics to do the same thing, but with no success. What I’m doing wrong here?

here is the class code:

FPSObjectiveActor.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FPSCharacter.h" 
#include <functional> 
#include <mutex> 
#include <atomic> 
#include "FPSObjectiveActor.generated.h"


typedef std::function<void()> CallbackFunction; 
class USphereComponent; 
class AFPSCharacter; 


UCLASS()
class FPSGAME_API AFPSObjectiveActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AFPSObjectiveActor();

protected:

	AFPSCharacter* _playerCharacter;
	CallbackFunction _callback;	
	
	/** <GAMEDEV> Static mesh component */
	UPROPERTY(VisibleAnywhere, Category = "Components") 
	UStaticMeshComponent* _meshComp; 

	/** <GAMEDEV> Collision component */
	UPROPERTY(VisibleAnywhere, Category = "Components") 
	USphereComponent* _sphereComp; 
		
	// <GAMEDEV> Particle system component
	UPROPERTY(EditDefaultsOnly, Category = "Effects") 
	UParticleSystem* _pickUpFX; 

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	void PlayEffects(); /

	void setCallback(CallbackFunction _cb);
	
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// <GAMEDEV> Method used to notify when this actor overlaps another one 
	virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;

};



FPSObjectiveActor.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FPSObjectiveActor.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Kismet/GameplayStatics.h" 
#include "FPSCharacter.h" 
#include <mutex> 
#include <atomic> 

//#define CALLBACK_CALLED ([]() {static bool is_first_time = true; auto was_first_time = is_first_time; is_first_time = false; return was_first_time; })
#define CALLBACK_CALLED []()->bool {static std::atomic<bool> first_time(true); return first_time.exchange(false); }

// Sets default values
AFPSObjectiveActor::AFPSObjectiveActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false; 

	_meshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp")); 
	_meshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision); 
	RootComponent = _meshComp; 

	_sphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp")); 
	_sphereComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly); 
	_sphereComp->SetCollisionResponseToAllChannels(ECR_Ignore); 
	_sphereComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
	_sphereComp->SetupAttachment(_meshComp); 

	/*if(CALLBACK_CALLED) {	
		auto& _tmp = _playerCharacter; 
		setCallback([&_tmp]() { return _tmp->PrintObjectiveMessage(); });
	}*/

	std::once_flag _wasCallbackExecuted;

	std::call_once(
		_wasCallbackExecuted,
		[this]() {
			auto& _tmp = _playerCharacter; 
			setCallback([&_tmp]() { return _tmp->PrintObjectiveMessage(); });	

		}
	);
	
	//auto& _tmp = _playerCharacter; 
	//setCallback([&_tmp]() { return _tmp->PrintObjectiveMessage(); });

}

void AFPSObjectiveActor::PlayEffects()
{
	UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), _pickUpFX, GetActorLocation()); 

}
    
void AFPSObjectiveActor::setCallback(CallbackFunction _cb)
{
	_callback = _cb;
	UE_LOG(LogTemp, Warning, TEXT("Callback bound"));

}

// Called when the game starts or when spawned
void AFPSObjectiveActor::BeginPlay()
{
	Super::BeginPlay();

	PlayEffects();    	
	
}

// Called every frame
void AFPSObjectiveActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}
    
void AFPSObjectiveActor::NotifyActorBeginOverlap(AActor* _otherActor)
{
	Super::NotifyActorBeginOverlap(_otherActor);
		
	 _playerCharacter = Cast<AFPSCharacter>(_otherActor);	
	if (_playerCharacter) { 
		PlayEffects();
		_playerCharacter->_bIsCarryingObjective = true; 		
		_callback();		
		Destroy();
	}
		
}

Here is an image containing the result after using the std::cal:once approach, you can the yellow phrases inside the output window, there are three of them:

And here is an image containing the result after I uncomment the macro and the IF statement:

In both cases, what I’m doing wrong?

Any help will be greatly appreciated!

Thanks!

You need to learn UE4 conventions because you tripping yourself up as rest UE4 code expect you to code according to it while interactin with UE4 APIs.

First of all you should not put any game play code in constructor. Constructor is called on module initiation (and in case of editor it means when you turn editor on) to create Class Default Object storing defaults. Constructor in UObject based class is intended to be used only to set default state of object nothing else it also being executed in early stage of engine init so you wont have access to everything (If you not aware yet, your module is not some magical thing run on some VM, it is full blow enigne module which is included to already huge UE4 code base, you effectively extending the engine so your code need to cooperate with it, if you code crash the entire engine crash), defaults should also bot be based on dynamic conditions. UObject and AActor have set of overridable functions allowing to execute code on many stages of object creation,

You also need to remember that you code is executed in level editor too (yes you can extend behavior of your actor in level editor), so you should BeginPlay event.

2nd thing is used of standard C++, UE4 has it’s own standard library, which either wraps standard C++ library or have it own raw independent implementations like containers for example, it also have it own implementation of multi threading support (which call_once seem to be coming form). Reason behind it allows your code and UE4 overall to be easily port to many platforms and also implement game oriented and platform dependent low level optimizations that standard C++ library implementations (which each platform has it own) won’t give, engine also use that to monitor what is happening in your and UE4 code while direct standard lib C++ calls would not allow. Because all of this it is highly not recommended to use standard C++ library, UE4 don’t expect you to use it and UE4 APIs are not compatible with it, it only create issues.

Now to issue it self… i don’t know why you complicate your life with std:call_once which seem to be made primerly for multithreading in first place on something that will run on single thread :stuck_out_tongue: If you follow UE4 game play framework, stuff like objective tracking should be done in GameMode (for all players) or PlayerController (for individual players), that system that you could make would track if the objective that your object depend is already set. That would been typical UE4 dev would take or something similar. You need to remember that Blueprint and C++ framework wise are very similar, in fact majority of blueprint nodes are direct bindings of C++ functions or simple wrap of few calls because blueprint incompatibility with C++. So you do game play code in C++ you need ot think exact same way as you do with blueprints.

Thanks for your reply! I’ll read the conventions, refactor the code and then i’ll update this thread later =)

Also, a guy from another forum said almost the same things that you said, that , as a good practice, I shouldn’t use anything outside UE4 API, and that I should avoid the standard C++ APIs. And about the constructor, I did now about it, that it should be used to initialize the default state only, that there’s no world created before the constructor call and I read that contructors are called before the PostInitializeComponents and BeginPlay.

My doubt is: should I use delegate to make a PlayerController listen for a BeginOverlap event and react to it, change the objective state inside this controller and print a objective message on screen, as an alternative to the typedef std::function used to created a callback (standard c++), ?

There ealier events then that but yes, those 2 are early the same but BeginPlay only starts in game, while 1st even is called also in level editor when you place actor.

Yes that what delegates been made for, go ahead ^^ delegates are equivalent of event dispatchers in blueprints. I would do this little bit different, i would make event function in actor itself and then call objective changing function, this way when you want to create different types of objectives you don’t need to edit PlayerController.

Also UE4 APIs got a lot of equivlents for standard lib ;]:

but you should use delegates