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"

Crash when accessing a custom C++ class

I'm trying to make a talent tree system on C++ based on two classes, a Talent class to store simple data and a TalentTree class to store, manage and access a list of talents. Since they both share the same purpose, both ae in the same source files (TalentTree.h/.cpp) Everything seems to be working as intended, but when I try to access a talent from the list in my GameMode class it causes UE4 to crash.

I may not be initializing everything as needed, but I can't find any answers on why it doesn't work. I've tried changing the classes that inherit from it a few times, but I started inheriting both from UObject. Here's my code, with :

TalentTree.h,

 UTalent:
     UCLASS()
     class PROJECTWAIFU_API UTalent : public UObject
     {
         GENERATED_BODY()
     
         UPROPERTY()
             int id;
         UPROPERTY()
             int level;
         UPROPERTY()
             FString name;
     
     public:
         UTalent(const FObjectInitializer &ObjectInitializer);
     
         UTalent(FString _name, int32 _id);
     
         // Getters and setters
         UFUNCTION()
             void SetLevel(int _lvl) { level = _lvl; }
         UFUNCTION()
             int GetLevel() { return level; }
         UFUNCTION()
             void SetID(int _id) { id = _id; }
         UFUNCTION()
             int GetID() { return id; }
         UFUNCTION()
             void SetName(FString _name) { name = _name; }
         UFUNCTION(BlueprintCallable, Category = "Talent Tree")
             FString GetName();
     
         UFUNCTION()
             void ResetLevel() { level = 0; }
         UFUNCTION()
             void LevelIncrease() { level++; }
     };

TalentTree.cpp,

 UTalent:
     UTalent::UTalent(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer)
     {
         level = 0;
     }
     
     UTalent::UTalent(FString _name, int _id)
     {
         name = _name;
         id = _id;
         level = 0;
     }
     
     FString UTalent::GetName() 
     { 
         return name; 
     }

TalentTree.h,

 ATalentTree:
 
     UCLASS()
     class PROJECTWAIFU_API ATalentTree : public AActor
     {
         GENERATED_BODY()
     
             UPROPERTY()
             TArray<UTalent*> TalentList;
         
     public:
         ATalentTree(const FObjectInitializer &ObjectInitializer);
     
         virtual void BeginPlay() override;
         
         UFUNCTION(BlueprintCallable, Category = "Talent Tree")
             UTalent* FindByID(int _id);
     };

TalentTree.cpp,

  ATalentTree(with one WIP method):
     ATalentTree::ATalentTree(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer)
     {
     }
     
     void ATalentTree::BeginPlay()
     {
         UTalent* t = NewObject<UTalent>();
         t->SetID(1);
         t->SetName("Test talent");
         TalentList.Add(t);
     }
     
     UTalent* ATalentTree::FindByID(int _id)
     {
         return TalentList[0];
     
         return nullptr;
     }
Product Version: UE 4.12
Tags:
more ▼

asked Oct 20 '16 at 03:26 PM in C++ Programming

avatar image

Herreteman
5 2 4 6

avatar image Doug E ♦♦ STAFF Oct 20 '16 at 04:10 PM

Hey Herreteman-

Can you provide the callstack and log files from the crash to indicate where the crash is occurring? Does the crash occur when you press play or during a specific action? Are you trying to access a specific talent from your game mode or does the crash happen when you access any talent from the game mode? Can you post the code where you're accessing this class from your game mode as well?

avatar image Herreteman Oct 20 '16 at 04:31 PM

The crash will consistently happen when pressing play, but just because the time I try to access a talent is on a BeginPlay. Right now, as I was just testing if it worked, I have one talent initialized and I access it directly on my test function FindByID(int _id), so it should happen with any talent.

Here's the crash log: http://pastebin.com/NvANRGe4

avatar image Doug E ♦♦ STAFF Oct 20 '16 at 05:17 PM

The crash logs indicate an access violation when the call to FindByID is made (at line 42 of your talenttree.cpp file). Can you run the project in debug mode and let me know if the TalentList array (specifically element 0) is populated?

avatar image Herreteman Oct 21 '16 at 04:22 PM

Sorry for the late response, I didn't have access to my project for a day.

According to debug, the TalentList array isn't populated, which means I forgot something when initializing it. In traditional C++ the code shouldn't have any problem, so I may be missing something on UE4's part.

avatar image Shadowriver Oct 21 '16 at 04:35 PM

TArray crashes if you attempt reading non-existing index (in native array it would return junk or crash if there is nothing allocated in accessing address), do check if requested id exists with this function:

https://docs.unrealengine.com/latest/INT/API/Runtime/Core/Containers/TArray/IsValidIndex/index.html

(comments are locked)
10|2000 characters needed characters left

2 answers: sort voted first

Declaring your object constructor is pretty straightforward. You'll want it to be public, and it's just the class name with no arguments:

 public:
 
     ATalentTree();

In the source you can call the constructor of parent objects via the initialization list, as well as set default values for you variables.

 ATalentTree::ATalentTree()
     :
     AActor()//<-- parent constructor
 {
     //perform any construction tasks here, as normal
 }

Some older tutorials and example code include the FObjectInitializer argument, but that's no longer passed in; and most (if not all) of its functionality is natively accessible within the constructor method.

If you've declared the variable in your game mode header, remember you still need to manually spawn the actor.

You can do it in your constructor using CreateDefaultSubobject or CreateOptionalDefaultSubobject. If the object you're creating is a UObject you can also use the standard NewObject method; but within the game mode constructor you can't use SpawnActor because the world doesn't yet exist.

Outside your constructor you should use NewObject or SpawnActor, depending on which type of object you're building.

Each of them is templated, and has a number of different forms.

For your ATalentTree you'll want to declare and instantiate it like this:

 //.h
 
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Talents")
 ATalentTree* TalentTree;


 //.cpp
 AMyGameMode::AMyGameMode() 
     :
     AGameMode()
 {

     //either of these should work to spawn your actor
   
     //this
     TalentTree = CreateDefaultSubObject<ATalentTree>();
 
     //or this
     TalentTree = CreateOptionalDefaultSubObject<ATalentTree>();
 
 }



https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/UWorld/SpawnActor/index.html

https://docs.unrealengine.com/latest/INT/API/Runtime/CoreUObject/UObject/FObjectInitializer/CreateDefaultSubobject/index.html

https://docs.unrealengine.com/latest/INT/API/Runtime/CoreUObject/UObject/FObjectInitializer/CreateOptionalDefaultSubobject/index.html

more ▼

answered Oct 22 '16 at 02:50 AM

avatar image

GigasightMedia
1.7k 42 11 60

avatar image Herreteman Oct 22 '16 at 03:40 AM

I was missing CreateDefaultSubobject! I've used this when initializing components like meshes but I didn't know it was necessary to call a constructor. I just assumed the constructors were called in the same way as normal C++.

Thanks for helping me figure it out.

avatar image GigasightMedia Oct 22 '16 at 03:44 AM

No problem, glad to help.

(comments are locked)
10|2000 characters needed characters left

When and where are you calling FindByID? It may be that you are trying to access FindByID before BeginPlay is called.

You can place your initialization in the constructor:

 ATalentTree::ATalentTree()
     :
     AActor()
 {
     UTalent* t = NewObject<UTalent>();
     if (t) {
         t->SetID(1);
         t->SetName("Test talent");
         TalentList.Emplace(t);
     }
 }

In any event, it's probably a good idea to do a check before accessing the array members:

     UTalent* ATalentTree::FindByID(int _id)
     {
         if (TalentList.IsValidIndex(0)) {
             return TalentList[0];
 
         }
         return nullptr;
 
     }


more ▼

answered Oct 21 '16 at 04:34 PM

avatar image

GigasightMedia
1.7k 42 11 60

avatar image Herreteman Oct 21 '16 at 05:23 PM

This looked like the way to go, but it doesn't quite work. It seems to be crashing when I call TalentList.IsValidIndex(0)...

As for when I'm calling it, right now it's called inside a function in my custom GameMode class that needs to be called in other classes, and I call it as a test inside a Character Blueprint class using an input event.

avatar image GigasightMedia Oct 21 '16 at 05:46 PM

In looking at your UTalent class again, I notice you're overriding the constructor. I don't think UE4 will allow you to do this (you shouldn't use "new" at any point). It's also an older version of the native constructor. That might be the problem; when it accesses the array of UTalent pointers it freaks out.

Try just this as your constructor declaration:

 UTalent();

Also, to expose your ATalentTree to the character blueprint, you'll want to modify the UCLASS macro:

      UCLASS(BlueprintType, Blueprintable)
      class PROJECTWAIFU_API ATalentTree : public AActor

If that doesn't help, please post the contents of the ATalentTree and UTalent header and source files so we're sure we're all on the same page with the current state; and post the log file with the new crash data.

avatar image Herreteman Oct 21 '16 at 11:05 PM

I didn't think about constructors so I started messing with them and using your recommended constructor. Doing some debug messages I discovered that the constructor for ATalentTree is never called, so it would explain the invalid data.

I only have an ATalentTree inside my custom GameMode for now, but it should be calling the constructor. Is there some specific constructor rule in UE4 that I'm missing?

avatar image GigasightMedia Oct 22 '16 at 02:48 AM

Declaring your object constructor is pretty straightforward. You'll want it to be public, and it's just the class name with no arguments:

 public:
 
     ATalentTree();

In the source you can call the constructor of parent objects via the initialization list, as well as set default values for you variables.

 ATalentTree::ATalentTree()
     :
     AActor()//<-- parent constructor
 {
     //perform any construction tasks here, as normal
 }

Some older tutorials and example code include the FObjectInitializer argument, but that's no longer passed in; and most (if not all) of its functionality is natively accessible within the constructor method.

If you've declared the variable in your game mode header, remember you still need to manually spawn the actor.

You can do it in your constructor using CreateDefaultSubobject or CreateOptionalDefaultSubobject. If the object you're creating is a UObject you can also use the standard NewObject method; but within the game mode constructor you can't use SpawnActor because the world doesn't yet exist.

Outside your constructor you should use NewObject or SpawnActor, depending on which type of object you're building.

Each of them is templated, and has a number of different forms.

For your ATalentTree you'll want to declare and instantiate it like this:

 //.h
 
 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Talents")
 ATalentTree* TalentTree;


 //.cpp
 AMyGameMode::AMyGameMode() 
     :
     AGameMode()
 {

     //either of these should work to spawn your actor
   
     //this
     TalentTree = CreateDefaultSubObject<ATalentTree>();
 
     //or this
     TalentTree = CreateOptionalDefaultSubObject<ATalentTree>();
 
 }


(comments are locked)
10|2000 characters needed characters left
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