Initializing new Class / Object instance

I come from a C# background, this might be quite obvious for people that are familiar with C++.

When I want to create a new Object in C# I use something like this.


SendablePacket packet = new SendablePacket();

Where SendablePacket is the class I want to instantiate.

On my UE4 project I try to do the same thing, but cannot use the new keyword.
So I use what to my mind seems like the class constructor.


SendablePacket packet = SendablePacket();

Now, my main problem is that when I do that, it is like there is no new instance of the class.
All the containded variables for the “new” class are the same.
So I guess a new instance is never constructed.

How can I create a new instance of a class?

Source code of my files.

SendablePacket.h


#include "CoreMinimal.h"

class EPICDRAGONWORLD_API SendablePacket
{
public:
    SendablePacket();
    ~SendablePacket();

    static void WriteString(FString value);
    static void WriteByte(uint8_t value);
    static void WriteShort(uint16_t value);
    static void WriteInt(uint32_t value);
    static void WriteLong(uint64_t value);
    static void WriteFloat(float fvalue);
    static void WriteDouble(double dvalue);
    static uint8_t* GetSendableBytes();
    static uint16_t GetSize();
};

SendablePacket.cpp


#include "SendablePacket.h"
#include <EpicDragonWorld\BitConverter.h>

uint8_t* writeBuffer;
uint16_t writeBufferSize;

SendablePacket::SendablePacket()
{
    writeBuffer = new uint8_t[0];
    writeBufferSize = 0;
}

SendablePacket::~SendablePacket()
{
}

void SendablePacket::WriteString(FString value)
{
    if (!value.IsEmpty())
    {
        // Since we use short value maximum byte size for strings is 32767.
        // Take care that maximum packet size data is 32767 bytes as well.
        // Sending a 32767 byte string would require all the available packet size.

        // Convert to byte array.
        TArray<TCHAR> byteArray = value.GetCharArray();

        // Write string size.
        size_t size = sizeof(byteArray);
        WriteByte((uint8_t)size);
        WriteByte((uint8_t)(size >> 8));

        // Write string bytes.
        for (uint16_t i = 0; i < size; i++)
        {
            WriteByte(byteArray*);
        }
    }
    else
    {
        WriteByte(0);
    }
}

void SendablePacket::WriteByte(uint8_t value)
{
    uint8_t* newArray = new uint8_t[writeBufferSize + 1];
    for (uint16_t i = 0; i < writeBufferSize; i++)
    {
        newArray* = writeBuffer*;
    }
    newArray[writeBufferSize++] = value;
    delete] writeBuffer;
    writeBuffer = newArray;
}

void SendablePacket::WriteShort(uint16_t value)
{
    WriteByte(value);
    WriteByte(value >> 8);
}

void SendablePacket::WriteInt(uint32_t value)
{
    WriteByte(value);
    WriteByte(value >> 8);
    WriteByte(value >> 16);
    WriteByte(value >> 24);
}

void SendablePacket::WriteLong(uint64_t value)
{
    WriteByte(value);
    WriteByte(value >> 8);
    WriteByte(value >> 16);
    WriteByte(value >> 24);
    WriteByte(value >> 32);
    WriteByte(value >> 40);
    WriteByte(value >> 48);
    WriteByte(value >> 56);
}

void SendablePacket::WriteFloat(float fvalue)
{
    int32_t value = BitConverter::SingleToInt32Bits(fvalue);
    WriteByte(value);
    WriteByte(value >> 8);
    WriteByte(value >> 16);
    WriteByte(value >> 24);
}

void SendablePacket::WriteDouble(double dvalue)
{
    int64_t value = BitConverter::DoubleToInt64Bits(dvalue);
    WriteByte(value);
    WriteByte(value >> 8);
    WriteByte(value >> 16);
    WriteByte(value >> 24);
    WriteByte(value >> 32);
    WriteByte(value >> 40);
    WriteByte(value >> 48);
    WriteByte(value >> 56);
}

uint8_t* SendablePacket::GetSendableBytes()
{
    uint8_t* result = new uint8_t[writeBufferSize + 2];

    // TODO: Encrypt bytes.
    // unsigned char* encryptedBytes = Encryption.Encrypt(writeBuffer);
    uint8_t* encryptedBytes = writeBuffer;

    // Create two bytes for length (short - max length 32767).
    uint16_t resultPos = 0;
    result[resultPos++] = (uint8_t)writeBufferSize;
    result[resultPos++] = (uint8_t)(writeBufferSize >> 8);

    // Join bytes.
    for (uint16_t i = 0; i < writeBufferSize; i++)
    {
        result[resultPos++] = encryptedBytes*;
    }

    // Cleanup.
    delete] encryptedBytes;

    // Return the data.
    return result;
}

uint16_t SendablePacket::GetSize()
{
    return writeBufferSize + 2;
}

Full project sources at https://github.com/PantelisAndrianakis/EpicDragonWorldClient_UE4/tree/master/Source/EpicDragonWorld

Forgot to mention.
Because of what I wrote above I initialize the variable in the constructor(?).

Like this.

If I do not do that, writeBufferSize keeps increasing (because obviously is the same variable used), writeBuffer as well.

I’d google C++ Pointers and give yourself a quick tutorial of them.

The C# version of:



SendPacket MyPacket = new SendPacket();


Under the hood, that line is actually this (which is the proper C++ version):



SendPacket* MyPacket = new SendPacket();


C# hides pointers / memory management from you. Read through pointers real quick on whatever tutorial website you can find and things should make more sense.

Also note that you can create them using “new”, what you can’t do in Unreal is create Unreal Objects using “new” keyword.

Thank you for your help.
Apparently I need to use pointers like explained.


SendPacket* MyPacket = new SendPacket();

:rolleyes:

But even so, my writeBufferSize variable seems to be shared among new instances.
Do I have to declare it somehow?

Update. Found a solution.
After removing the header files and made a single cpp file it finaly worked as expected.

So the class looks like this now.


#include "CoreMinimal.h"
#include <EpicDragonWorld\BitConverter.h>

class EPICDRAGONWORLD_API SendablePacket
{
private:
    uint8_t* writeBuffer = new uint8_t[0];
    uint16_t writeBufferSize = 0;

public:
    SendablePacket()
    {
    }

    ~SendablePacket()
    {
    }

    void WriteString(FString value)
    {
        if (!value.IsEmpty())
        {
            // Since we use short value maximum byte size for strings is 32767.
            // Take care that maximum packet size data is 32767 bytes as well.
            // Sending a 32767 byte string would require all the available packet size.

            // Convert to byte array.
            TArray<TCHAR> byteArray = value.GetCharArray();

            // Write string size.
            size_t size = sizeof(byteArray);
            WriteByte((uint8_t)size);
            WriteByte((uint8_t)(size >> 8));

            // Write string bytes.
            for (uint16_t i = 0; i < size; i++)
            {
                WriteByte(byteArray*);
            }
        }
        else
        {
            WriteByte(0);
        }
    }

    void WriteByte(uint8_t value)
    {
        uint8_t* newArray = new uint8_t[writeBufferSize + 1];
        for (uint16_t i = 0; i < writeBufferSize; i++)
        {
            newArray* = writeBuffer*;
        }
        newArray[writeBufferSize++] = value;
        delete] writeBuffer;
        writeBuffer = newArray;
    }

    void WriteShort(uint16_t value)
    {
        WriteByte(value);
        WriteByte(value >> 8);
    }

    void WriteInt(uint32_t value)
    {
        WriteByte(value);
        WriteByte(value >> 8);
        WriteByte(value >> 16);
        WriteByte(value >> 24);
    }

    void WriteLong(uint64_t value)
    {
        WriteByte(value);
        WriteByte(value >> 8);
        WriteByte(value >> 16);
        WriteByte(value >> 24);
        WriteByte(value >> 32);
        WriteByte(value >> 40);
        WriteByte(value >> 48);
        WriteByte(value >> 56);
    }

    void WriteFloat(float fvalue)
    {
        int32_t value = BitConverter::SingleToInt32Bits(fvalue);
        WriteByte(value);
        WriteByte(value >> 8);
        WriteByte(value >> 16);
        WriteByte(value >> 24);
    }

    void WriteDouble(double dvalue)
    {
        int64_t value = BitConverter::DoubleToInt64Bits(dvalue);
        WriteByte(value);
        WriteByte(value >> 8);
        WriteByte(value >> 16);
        WriteByte(value >> 24);
        WriteByte(value >> 32);
        WriteByte(value >> 40);
        WriteByte(value >> 48);
        WriteByte(value >> 56);
    }

    uint8_t* GetSendableBytes()
    {
        uint8_t* result = new uint8_t[writeBufferSize + 2];

        // TODO: Encrypt bytes.
        // unsigned char* encryptedBytes = Encryption.Encrypt(writeBuffer);
        uint8_t* encryptedBytes = writeBuffer;

        // Create two bytes for length (short - max length 32767).
        uint16_t resultPos = 0;
        result[resultPos++] = (uint8_t)writeBufferSize;
        result[resultPos++] = (uint8_t)(writeBufferSize >> 8);

        // Join bytes.
        for (uint16_t i = 0; i < writeBufferSize; i++)
        {
            result[resultPos++] = encryptedBytes*;
        }

        // Cleanup.
        delete] encryptedBytes;

        // Return the data.
        return result;
    }

    uint16_t GetSize()
    {
        return writeBufferSize + 2;
    }
};

Link to the complete commit: https://github.com/PantelisAndrianakis/EpicDragonWorldClient_UE4/commit/7e0a92ca22462a20483fa9f0542a9ba17950a3bb