I'm working with C++ queues. First, I make a push (the copy constructor is called and works fine) and when I do a simple pop, it calls the first destructor method (not the new created). Here a sample code:
{
T_MENSAJE new_msg; // Constructor 1 called -> Instance 1
new_msg.rellena(msg);
m_messages.push(new_msg); // Copy constructor called -> Instance 2
m_messages.pop(); // Destructor of instance 1 called !!!!!!!
return; // again, destructor of instance 1 called
}
Edit:
For demonstrate it, I show the memory direction of m_data, into rellena(msg); constructor copy method and in the destroyer. In rellena, has memDir1, in copy constructor memDir2, as I expectyed. But when I call pop method, the destroyer method shows memDir1 (not memDir2 as I expected), then when the function finish, the destroyer is called again and memDir1 is shown again. Here is the T_MENSAJE struct:
typedef struct T_MENSAJE
{
T_MSG_HEADER m_cab;
char m_command[MSG_COMMAND_SIZE];
char* m_data;
T_MENSAJE():m_data(0){
}
~T_MENSAJE()
{
static int counter = 0;
if (m_data != 0)
{
printf("%s -- direction = %d\n",__FUNCTION__,m_data);
delete[](m_data);
}
}
T_MENSAJE(const T_MENSAJE& m)
{
m_cab = m.m_cab;
memcpy(&m_command,&m.m_command,MSG_COMMAND_SIZE);
if (m.m_data != 0)
{
int numBytes = m_cab.m_lenght-MSG_HEADER_SIZE-MSG_COMMAND_SIZE;
m_data = new char[numBytes];
printf("%s -- direction = %d\n",__FUNCTION__,m_data);
memcpy((char*)&(m_data),&m.m_data, numBytes);
}else
{
m_data = 0;
}
}
......
......
......
}
The memcpy memcpy((char*)&(m_data),&m.m_data, numBytes); copies numBytes from the address of &m.m_data to the address of your member m_data. This is wrong and overwrites parts of your object.
Related
I am asking this question from an Unreal Engine C++ code point of view but I am wondering if my problem is more to do with the nuances of C++'s way of operating.
I have a Unreal actor. A simple class that holds an array of my own structs and runs a timer which triggers my own function. This function passes a reference of the actors array to an asynchronous task.
This async task then goes to work, first creating a new struct, then adding two floats to its own internal TArray of floats and then adds that struct to the main actors array.
The problem:
After the async task has completed and I delete the actor from the level editor window, the system RAM is decreased as I call the Empty() function on the main actors array in the Destroyed() function but the RAM used by all of the structs (ie: The float array inside each struct) is left in memory and never cleared out.
Observations:
If I do not use an async task and run the same function inside the main thread ALL of the memory is cleared successfully.
If I do not create the struct inside the async task and instead initalize the array with a load of structs which in turn are initialized with N number of floats inside the main thread, then pass that as a reference to the async task which works on the data, then the memory is also cleared out successfully.
What I would like to happen
I would like to pass a reference of the main actors array of structs to the async task. The async task would then go to work creating the data. Once it is complete, the main actor would then have access to the data and when the actor is deleted in the level editor window, ALL of the memory would be freed.
The code:
The definition of the data struct I am using:
struct FMyDataStruct
{
TArray<float> ArrayOfFloats;
FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
FMyDataStruct(int32 FloatCount)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
~FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
};
The main actors definition of the array I am using:
TArray<FMyDataStruct> MyMainArray;
The main actors custom function I am running:
//CODE 1: This part DOES empty the RAM when run (ie: Run on main thread)
/*for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}*/
//CODE 2: This does NOT empty the RAM when run. The two floats * 50,000,000 are left in system memory after the actor is deleted.
auto Result = Async(EAsyncExecution::Thread, [&]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}
});
An example of initializing the array in the main thread, then working on it inside the async task:
//Initialize the array and its structs (plus the float array inside the struct)
MyMainArray.Init(FMyDataStruct(2), 50000000);
//TFuture/Async task
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
//Call the main threads task completed function
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->MyTaskComplete();
}
});
});
Final thoughts:
Ultimately what I am asking is can anyone explain to me why from a C++ point of view the structs and their data would be removed from memory successfully when created/added from the main thread but then not removed from memory if created inside the async task/thread?
Update #1:
Here is a minimum reproducible example:
Create a new project in either Unreal Engine 4.23, 4.24 or 4.25.
Add a new C++ actor to the project and name it "MyActor".
Edit the source with the following:
MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
struct FMyDataStruct
{
FMyDataStruct()
{
//Default Constructor
}
FMyDataStruct(const FMyDataStruct& other)
: ArrayOfFloats(other.ArrayOfFloats)
{
//Copy constructor
}
FMyDataStruct(FMyDataStruct&& other)
{
//Move constructor
if (this != &other)
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
}
FMyDataStruct& operator=(const FMyDataStruct& other)
{
//Copy assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = other.ArrayOfFloats; //UE4 TArray deep copy
}
return *this;
}
FMyDataStruct& operator=(FMyDataStruct&& other)
{
//Move assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
return *this;
}
FMyDataStruct(int32 FloatCount)
{
//Custom constructor to initialize the float array
if (FloatCount > 0)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
}
~FMyDataStruct()
{
//Destructor
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
public:
TArray<float> ArrayOfFloats;
};
UCLASS()
class BASICPROJECT1_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:
virtual void Destroyed() override;
public:
bool IsEditorOnly() const override;
bool ShouldTickIfViewportsOnly() const override;
virtual void Tick(float DeltaTime) override;
void DoSomething();
void AsyncTaskComplete();
bool bShouldCount = true;
float TimeCounter = 0.f;
TArray<FMyDataStruct> MyMainArray;
};
MyActor.cpp
#include "MyActor.h"
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor::Tick(float DeltaTime)
{
if (!HasAnyFlags(RF_ClassDefaultObject)) //Check for not CDO. We only want to run in the instance
{
if (bShouldCount)
{
TimeCounter += DeltaTime;
if (TimeCounter >= 5.f)
{
bShouldCount = false;
DoSomething();
}
}
}
}
void AMyActor::Destroyed()
{
Super::Destroyed();
MyMainArray.Empty();
MyMainArray.Shrink();
UE_LOG(LogTemp, Warning, TEXT("Actor got Destroyed!"));
}
bool AMyActor::IsEditorOnly() const
{
return true;
}
bool AMyActor::ShouldTickIfViewportsOnly() const
{
return true;
}
void AMyActor::DoSomething()
{
//Change the code that is run:
//1 = Main thread only
//2 = Async only
//3 = Init on main thread and process in async task
//======================
int32 CODE_SAMPLE = 1;
UE_LOG(LogTemp, Warning, TEXT("Actor is running DoSomething()"));
TWeakObjectPtr<AMyActor> Self = this;
if (CODE_SAMPLE == 1)
{
//CODE 1: Run on main thread. This part DOES empty the RAM when run. BLOCKS the editor window.
//=========================================================================
MyMainArray.Empty();
MyMainArray.Shrink();
MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyMainArray.Emplace(MyDataStruct);
}
UE_LOG(LogTemp, Warning, TEXT("Main thread array fill is complete!"));
}
else if (CODE_SAMPLE == 2)
{
//CODE 2: Run on async task. This does NOT empty the RAM when run
//(4 bytes per float * 2 floats * 50,000,000 structs = 400Mb is left in system memory after the actor is deleted)
//=========================================================================
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
Self->MyMainArray.Empty();
Self->MyMainArray.Shrink();
Self->MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
Self->MyMainArray.Emplace(MyDataStruct);
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
else if (CODE_SAMPLE == 3)
{
//CODE 3: Initialize the array in the main thread and work on the data in the async task
//=========================================================================
MyMainArray.Init(FMyDataStruct(2), 50000000);
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
}
void AMyActor::AsyncTaskComplete()
{
UE_LOG(LogTemp, Warning, TEXT("Async task is complete!"));
}
Compile and run the project.
Drag the actor into the level editor window.
After 5 seconds the code will run and the RAM usage will increase to 1750Mb.
Select the actor in the outliner window and delete it.
The RAM usage will perform like this:
CODE 1: RAM is cleared out all the way to the starting RAM usage of 650Mb.
CODE 2: RAM is cleared down to 1000Mb and never returns to starting usage.
CODE 3: RAM is cleared out all the way to the starting RAM usage of 650Mb.
I thank you for your help.
So I have the cl_Page class:
class cl_Page{
public:
cl_Page(cl_LessonMoment *parent_param);
cl_Page(cl_SoftRoot *parent_param);
int parent_type;
cl_LessonMoment *parent_lmoment;
cl_SoftRoot *parent_softroot;
char id[256];
//<content>
//Backgrounds.
str_Color bgcolor;
cl_Image bgimage;
//Actual content
vector<cl_Textbox> textboxes;
vector<cl_Button> buttons;
vector<cl_Image> images;
//</content>
cl_Textbox* AddTextbox();
cl_Button* AddButton();
cl_Image* AddImage(char *filename = nullptr);
};
and the cl_Page constructors:
cl_Page::cl_Page(cl_LessonMoment *parent_param) : bgimage(nullptr){ //here is the segfault
parent_lmoment = parent_param;
parent_type = 1;
id[0] = '\0';
SetColor(bgcolor, 0xffffffff);
}
cl_Page::cl_Page(cl_SoftRoot *parent_param): bgimage(nullptr){ // or here if i call this constructor
/*parent_softroot = parent_param;
parent_type = 2;
id[0] = '\0';
SetColor(bgcolor, 0xffffffff);*/
}
What happens is that, no matter how I call the constructors, or no matter which one I call (the second is all commented out; so basically empty), global, local or dynamically, in a function or as a member object, I get a segmentation fault which appears to be right on the cl_Page::cl_Page(cl_LessonMoment *parent_param) : bgimage(nullptr){ line. The call stack looks like this:
#0 77C460CB strcat() (C:\WINDOWS\system32\msvcrt.dll:??)
#1 0022F168 ?? () (??:??)
#2 00401905 cl_Page::cl_Page(this=0x22fbe8, parent_param=0x0) (F:\Scoala\C++\EduSoftViewer_Parser\sources\classes\soft_tree\page.cpp:10)
#3 00402B8A main() (F:\Scoala\C++\EduSoftViewer_Parser\sources\main.cpp:11)
On some builds before I am writing this, (with exactly the same issue) the #1 position on the call stack, where now is ?? () (??:??) was ntdll!RtlDosApplyFileIsolationRedirection_Ustr() (C:\WINDOWS\system32\ntdll.dll:??).
So my question is: Does anybody know what is causing this? I really need to get this working.
If anything is unclear, just ask and I'll provide additional information.
EDIT: To clarify: I'm under Windows XP SP2 and running Code::Blocks with gcc.
EDIT 2: The cl_Image constructor:
cl_Image::cl_Image(char *filename_param){
if (filename == nullptr){
filename[0] = '\0';
}
else{
strcpy(filename, filename_param);
}
SetPosition(position, 0, 0);
id[0] = '\0';
visible = 1;
z_index = 0;
}
This class doesn't contain any object members, with the exception of a POD struct, position
EDIT 3: The cl_Image class:
class cl_Image{
public:
cl_Image(char* filename_param = nullptr);
str_Position position;
char filename[256];
char id[256];
bool visible;
int z_index;
};
str_Position is just a struct of 2 ints.
Pretty sure this is your problem:
cl_Image::cl_Image(char *filename_param){
if (filename == nullptr){ // <<==== filename??? try using the param.
filename[0] = '\0';
}
Try this:
cl_Image::cl_Image(char *filename_param){
if (filename_param == nullptr){
filename[0] = '\0';
}
I'll guess that bgimage can't be initialized with nullptr.
I have a memory issue with a class of mine. The issue occurs when I create an object in a member function of a class. It is about the class below. I removed the member functions because they aren’t necessary:
class User
{
private:
bool locked;
bool active;
std::vector<City> * userCitys;
UserData userData;
Credentials credentials;
The problem occurs when I call this function:
int User::addCity(CityData cityData)
{
lockUserObject(); //Everything is fine here
City cityToAdd; //When this object is created, the memory of userCitys will get overridden
cityToAdd.activate();
userCitys->push_back(cityToAdd);
int cityID = userCitys->size() - 1;
userCitys->at(cityID).editCityData(cityData);
unlockUserObject();
return cityID;
}
In the first place I created userCitys on the stack. For test purpose I placed it on the Heap. The address of userCitys get overridden by some data. I can’t find the problem. the City is just a basic class:
Part of the header:
class City
{
private:
bool active;
Supplies supplies;
std::vector<Building> buildings;
std::vector<Company> companies;
std::vector<Share> shares;
std::vector<Troop> troops;
CityData cityData;
Constructor:
City::City()
{
active = false;
}
How is it possible that userCitys get overridden? This all happens on a single Thread so that can’t be a problem. I tried a lot of thing, but I can’t get it to work. What is the best approach to find the problem?
Edit:
Lock function:
void User::lockUserObject()
{
for( int i = 0; locked ; i++)
{
crossSleep(Settings::userLockSleepInterval);
if( i >= Settings::userLockMaxTimes )
Error::addError("User lock is over userLockMaxTimes",2);
}
locked = true;
}
I call the code here (Test function):
City * addCity(User * user)
{
Location location;
location.x = 0;
location.y = 1;
CityData citydata;
citydata.location = location;
citydata.villagers = 0;
citydata.cityName = "test city";
int cityID = user->addCity(citydata); //addCity is called here
City * city = user->cityAction(cityID);;
if( city == NULL)
Error::addError("Could not create a city",2);
return city;
}
The add user (Test code):
User * addUser()
{
UserData test;
test.name = "testtest";
Credentials testc("testtest",3);
//Create object user
int userID = UserControle::addUser(test,testc);
User * user = UserControle::UserAction(userID);
if( user == NULL)
Error::addError("Could not create a user",2);
return user;
}
My test function:
void testCode()
{
User * user = addUser();
City * city = addCity(user);
}
This function in called in main:
int main()
{
testCode();
return 0;
}
Here are UserAction and addUser in UserControle:
int UserControle::addUser(UserData userdata, Credentials credentials)
{
int insertID = -1;
for( int i = 0; i < (int)UserControle::users.size(); i++)
{
if( !UserControle::users.at(i).isActive() )
{
insertID = i;
break;
}
}
User userToInsert(userdata,credentials);
if( insertID != -1 )
{
UserControle::users.insert( UserControle::users.begin() + insertID,userToInsert);
return insertID;
}
else
{
UserControle::users.push_back(userToInsert);
return UserControle::users.size() - 1;
}
}
User* UserControle::UserAction(int userID) //check all indexes if greater then 0!
{
if( (int)UserControle::users.size() <= userID )
{
Error::addError("UserAction is out of range",3);
return NULL;
}
if( !UserControle::users.at(userID).isActive())
{
Error::addError("UserAction, the user is not active.",3);
return NULL;
}
return &UserControle::users[userID];
}
There's a few things you could try:
Remove code until the fault goes away. In other words, distill a minimal example from your code. I guess you'll then see the error yourself, otherwise post that small example program here and others will.
Don't use raw pointers. The question with those is always who owns what they point to. Use smart pointers instead, e.g. unique_ptr (C++11) or auto_ptr (C++98) for exclusive ownership.
If you have pointer members like "userCities", you need to think about what happens when copying instances of that class (you already wrote a proper destructor, or?). So, either prevent copying (make copy-constructor and assignment operator private and without implementing it) or implement them in a way that the vectors are properly cloned and not shared between different instances.
Don't use C-style casts. If those are necessary to get anything through the compiler, the code is probably broken.
This code runs successfully and MQStruct constructor initialized the values as well, I can see in ExecuteThread function but in TestFunction, I get the garbage values for MQStruct.
I am passing address of struct "&MQStructObj" to _beginthreadex for parameters and This is the problem I guess
struct MQStruct {
MQStruct()
{
pointer=NULL;
serviceName=NULL;
durability=0;
msgType=0;
msgHeader=0;
msgId=NULL;
payload=NULL;
payloadSize=0;
ttl=0;
priority=0;
}
void* pointer;
wchar_t *serviceName;
int durability;
int msgType;
int msgHeader;
wchar_t *msgId;
wchar_t *payload;
int payloadSize;
int ttl;
int priority;
};
int ExecuteThread() {
HANDLE heartBeatThread;
unsigned int hbThreadID;
int result = 0;
MQStruct MQStructObj;
MQStructObj.pointer=this;
heartBeatThread = (HANDLE)_beginthreadex(NULL, 0 , &TestFunction, &MQStructObj, 0/*CREATE_SUSPENDED*/, &hbThreadID);
if ( heartBeatThread == 0 )
{
result = -1;
LogEvent(DEBUG_LOG,0, "Fail to create thread");
}
CloseHandle(heartBeatThread);
return result;
}
You guessed correctly.
You're passing the address of a local variable to your thread-proc-startup, then leaving scope (and destroying the object in the process). References to this object in your thread proc are there-after undefined behavior.
Dynamically allocate one with new and let the thread proc delete it.
MQStructObj is declared on the stack so will go out of scope and potentially be overwritten as soon as ExecuteThread completes.
If you want to use a stack object here, you'll need to add some synchronisation to allow your new thread to copy from MQStructObj before ExecuteThread returns.
Alternatively, normally preferably, you could allocate MQStructObj dynamically and leave the new thread to clean it up at its leisure
MQStruct* MQStructObj = new MQStruct();
MQStructObj->pointer=this;
heartBeatThread = (HANDLE)_beginthreadex(NULL, 0 , &TestFunction, MQStructObj, 0, &hbThreadID);
if ( heartBeatThread == 0 ) { // error
delete MQStructObj;
result = -1;
}
// ownership of MQStructObj transferred to new thread
There seems to be an issue with my dequeue function within a queue class that I have. My dequeue function which is part of the position class, is not returning the correct values that have been enqueued into the list.
The values that have been enqueued are which is a position object, are 2,1 and -1, but when I dequeue that object i get 2,506216, and -1; When I assign the *pos ponter to an object I am left with the default values;The enqueue function seems to be working correctly for when I check the ptr values they are correct.
//position constructor
front = back = &header;
struct Posnode
{
Position *pos;
Posnode *next;
};
class Position
private:
Posnode *front,*back,header;
void Position::dequeue(Position&p)
{
Posnode *ptr=front->next;
front->next = ptr->next;
p = *ptr->pos;
p.geta();//checking for values but am left with the default
if (back == ptr)
{
back = front;
}
delete ptr;
}
v
oid Position::enqueue(Position n) //assigning Position object to end of queue
{
Posnode *ptr = new Posnode;
ptr-> pos = &n;
back->next = ptr;
back = ptr;
return;
}
Position copy,intial(5);
copy = intial;
if (copy.ismovelegal(posmoves, r))
{
copy.makemove(posmoves, r);
if (intial.solved(copy))
{
cin.get();
}
else
{
p.enqueue(copy);
}
}
copy.free();//clearing object private memebers
}
intial.free();
p.dequeue(o);//copy that was previous enqued is not enqued
o.geta();
Just Check out the Implementation of Deque first and then try your own. If its some syntax or semantic error post minimal code that reproduces your code.
this link might help you. Deque Implementation