Download

SaveGameToSlot Access Violation : C++

Hello, I have implemented save functionality before, exactly as I am doing now, but in a new project. This project is throwing an error when saving, however, it is able to load correctly. When I call

UGameplayStatics::SaveGameToSlot(CurrSaveGame, CurrSlotName, CurrUserIndex);

it steps into Unreal Engine code and fails inside the UGameplayStatics::SaveGameToMemory. Specifically, it fails on line 2024, where it is trying to call SaveGameObject->Serialize(Ar); This throws an exception:

Exception thrown at 0x00007FFF7E70C5E0 (UE4Editor-Engine.dll) in UE4Editor.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

Using the call stack, I see that SaveGameToMemory is simply being called by SaveGameToSlot. Where SaveGameObject is my USaveGame*.

This leads me to believe I am setting up my USaveGame* class incorrectly. In my case, the class is called UHHSaveGame. Here is how I have that class setup.

USTRUCT()
struct FActorSaveData
{
    GENERATED_BODY()

public:

    UPROPERTY()
	FName ActorName;

    UPROPERTY()
	FTransform Transform;

    UPROPERTY()
	TArray<uint8> ByteData;
};


USTRUCT()
struct FPlayerSaveData
{
    GENERATED_BODY()

public:
    UPROPERTY()
	int32 CandyCount;
};


UCLASS()
class HOWLOWEEN_API UHHSaveGame : public USaveGame
{
     GENERATED_BODY()

public:

    UPROPERTY()
	FPlayerSaveData playerSaveData;

    UPROPERTY()
	TMap<FName, FActorSaveData> actorSaveData;
};

I am unsure what could be going wrong, if something I have is not serializable or what, but thank you so much for the help!

Access violation at that address is usually an attempt to call an uninitialized class via a nullptr. Consider the following:

  1. FName is not acceptable in the way that you are using it. It is a statically allocated object made available to your entire game → FName (Unreal Engine API reference)

    Recommended: change static allocated FName in instance to FString, bad use-case.

  2. A TMap is a dynamically allocated object. Do you see how a nullptr can result from this?

    Recommended: Grab a few c++ refresher courses. Specifically those on pointers, and static vs. dynamically allocated objects.

  3. References to other classes should be done with a pointer so that USaveGame can properly reference the object in memory. These are dynamically allocated objects and have to be referred to that way:

    Example A
    TArray<uint8>* ByteData (pointer)
    *ByteData (dereference to pointer target).

    Example B
    TMap<FString, FActorSaveData*>* actorSaveData (pointer)

    bool HenryExists = *actorSaveData->ContainsByPredicate([&](FString key, FActorSaveData* value){ return key == TEXT("HENRY") && *value->CandyCount != -1 ; });

    A dereference inside of map predicate to look for a FActorSaveData* pointer with the name “HENRY” where the game world has at least been initialized.

  4. You need to implement a constructor. USTRUCT() and UCLASS() both expect a constructor, and implimenting a destructor to call free() on any pointers and objects is recommended to keep your heap clean. You are referencing objects that do not exist, currently. If you would like to implement constructor overloads for your USTRUCT() and your UCLASS(), you may do so to make things more convenient for yourself.

    Recommended: Implement constructor and destructor and any overloads you wish to have to make convenient inline constructions.

Thank you for your help and all of this useful information to review! However, I actually solved the issue. The issue was resulting when I would load up the map, and then load back to the main menu and then load back. While the variable was being initialized, as I was not setting the USaveGame as a UPROPERTY() it was being garbage collected. Simply adding UPROPERTY() was all I needed to fix the issue.

1 Like

Glad to hear you got it fixed!