x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Is this the correct practice with UObjects and smart pointers?

Hello,

it's hard to find some documentation for this use case, and it's not yet very clear when to choose to use the various shared pointers, this is why I ask here if you think I did the things right:

I have a class UBBTeam inheriting from UObject, which has a reference to an other team, and holds a static array of weak pointers to some players (ABBCharacter). Each ABBCharacter is spawned regularly in the game mode. Moreover, each ABBCharacter holds a reference to another ABBCharacter, and a reference to his owning team. The owner of the teams is my ABBGameMode, which holds them in a static array of shared pointer.

Here are the interesting excerpts of the classes, where I have put in comments my various questions :

ABBMatchGameMode class declaration

 UCLASS(minimalapi)
 class ABBMatchGameMode : public AGameMode
 {
     GENERATED_UCLASS_BODY()

 public:

     virtual void PostInitializeComponents() OVERRIDE;

 private:

     // Is this the best way to store UObjects? Should I use UProperty() ?
     TStaticArray<TSharedPtr<UBBTeam>, 2> Teamtable;
 };

ABBMatchGameMode class implementation

 void ABBMatchGameMode::PostInitializeComponents()
 {
     Super::PostInitializeComponents();

     for ( int index = 0; index < 2; index++ )
     {
         // Not sure about that, but it seems to be the only way. But maybe TSharedPtr is not well suited for that?
         TSharedPtr<UBBTeam>
             team( NewObject<UBBTeam>( ) );

         Teamtable[ index ] = team;
     }

     Teamtable[ 0 ]->SetOtherTeam( *Teamtable[ 1 ] );
     Teamtable[ 1 ]->SetOtherTeam( *Teamtable[ 0 ] );
 }

UBBTeam class declaration:

 UCLASS()
 class UBBTeam : public UObject
 {
     GENERATED_UCLASS_BODY()

 public:

     void SetPlayer( ABBCharacter & player, const int team_position_index );
     void SetOtherTeam( const UBBTeam & other_team );

 private:

     // This one should be OK, I saw plenty of examples like this in the engine
     TStaticArray<TWeakObjectPtr<ABBCharacter>, 2> PlayersTable;

     // Is it okay to use TWeakObjectPtr for UObject?
     TWeakObjectPtr<UBBTeam> OtherTeam;
 };

UBBTeam class implementation:

 void UBBTeam::SetPlayer( ABBCharacter & player, const int team_position_index )
 {
     PlayersTable[ team_position_index ] = &player;
     player.SetTeam( *this );
 }

 // I prefer to pass C++ references generally. Should I use TSharedRef instead?
 void UBBTeam::SetOtherTeam( const UBBTeam & other_team )
 {
     check( &other_team != this );

     OtherTeam = &other_team;
 }

ABBCharacter class declaration:

 UCLASS(config=Game)
 class ABBCharacter : public ACharacter
 {
     GENERATED_UCLASS_BODY()

 public:

     void SetTeam( const class UBBTeam & team );
     void SetTeamMate( const ABBCharacter & team_mate );

 private:

     // Again, TWeakObjectPtr for both Actors and UObject. No problem?
     TWeakObjectPtr<class ABBCharacter> TeamMate;
     TWeakObjectPtr<class UBBTeam> Team;
 };

ABBCharacter class implementation:

 // C++ reference for a UObject, is it ok?
 void ABBCharacter::SetTeam( const UBBTeam & team )
 {
     check( !Team.IsValid() );

     Team = &team;
 }

 // C++ reference for a Actor, is it ok?
 void ABBCharacter::SetTeamMate( const ABBCharacter & team_mate )
 {
     check( !TeamMate.IsValid( ) );

     TeamMate = &team_mate;
 }

What do you think?

In the shooter game, I could see:

 UPROPERTY(Transient, Replicated)
 TArray<class AShooterWeapon*> Inventory;

 UPROPERTY(Transient)
 TArray<UMaterialInstanceDynamic*> MeshMIDs;

Does this mean that it is converted automatically to smart pointers under the hood?

Thanks :)

Product Version: Not Selected
Tags:
more ▼

asked Apr 02 '14 at 02:31 PM in C++ Programming

avatar image

Zoubi
172 22 30 35

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

You don't want to use TSharedPtr/TSharedRef/TWeakPtr with UObjects, those are designed for non UObjects.

UObjects use a garbage collection system. By declaring UPROPERTY() that essentially lets the garbage collection system know about that reference. If you declare just a UObject *, that is a Hard reference, which means that the referenced object will not be freed as long as their is a chain of references from the Root to that object. Here's an overview of the basics: https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Objects/Optimizations/index.html

So, if you want to reference a UObject, but don't want it to be a Hard reference that keeps it from being garbage collected, you then use TWeakObjectPtr. This will automatically be set to NULL when the referenced object is deleted, but it won't stop that object from getting deleted if no other references to it exist. This is useful for things like UI where you want to know about the state of an object, but can gracefully handle it going away when it dies.

more ▼

answered Apr 03 '14 at 08:38 PM

avatar image

[Epic]Ben Zeigler STAFF
1.3k 30 131 75

avatar image grisevg Nov 18 '15 at 11:07 AM

This is not correct - UObject * doesn't make a Hard/Root reference. UE4 has no idea about UObject * so it doesn't affect garbage collection, meaning that if object was garbage collected UObject * is not going to get nulled, which would cause all sorts of errors and issues. TWeakObjectPtr helps with that is it will be invalidated when the object is GCed.

To prevent object from garbage collection if it's not referenced anywhere, you can call AdddToRoot() on it.

avatar image mrooney Jan 06 '16 at 09:53 PM

You are wrong. UObject pointers automatically have their references cleaned up on destruction when they are marked as uproperties. It says so right in the link he gave you under the "Automatic Updating of References" section. What you say is only true if you don't mark them as UProperties.

avatar image Steazy Aug 18 '16 at 11:03 PM

I think the phrasing of this answer is misleading for people who aren't already familiar with these types of systems (reference counting, GC, preprocessor macros, etc).

Example: "By declaring UPROPERTY() that essentially lets the garbage collection system know about that reference." <= Correct

"If you declare just a UObject *, that is a Hard reference, which means that the referenced object will not be freed as long as their is a chain of references from the Root to that object." <= Correct, only given the previous statement, but the phrasing of the sentence implied to me that UPROPERTY was not needed for a hard reference (even though I knew that it must be).

Something like: If you declare a UObject * it is a raw C++ reference that the UE garbage collector will not know about (aka an unsafe pointer). The UObject may be collected, the pointer will not be NULL, and there will be no way to determine if the pointer is safe to use (hence unsafe pointer).

Marking the UObject * (unsafe pointer) with the UPROPERTY macro will automatically inform the GC of the reference - implicitly making it a hard reference (strong pointer). A UObject can not be freed until no hard references exist from the Root to that object.

A TWeakObjectPtr (weak pointer) allows referencing UObjects without preventing garbage collection. Remember that the referenced object may be collected while you aren't paying attention, so check IsValid() or Get() != nullptr or you will inadvertently free all the memory as your game crashes to desktop.

avatar image L4g0 Apr 25 '18 at 12:30 AM

Thank you for this explanation Steazy. I finally understand the reasons behind UPROPERTY and TWeakObjectPtr. I have not found a clearer explanation than this.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question