I'm currently writing an extension of another program (Specificly, of a game) and i've been stuck on solving the following problem for hours now.
Any time a player (client) connects to the game server, the OnClientConnected(int client_number); function is called. In this function, i create an instance of a CPlayer class that stores player information, such as health, speed and any other data i might require. This instance, is then stored by the following class:
class CPlayerManager
{
std::vector<Player*> *player_list;
public:
CPlayerManager();
~CPlayerManager();
void AddPlayer(client_id)
*CPlayer GetPlayerInstance(client_id);
}
CPlayerManager()
{
player_list = new std::vector<Player*>;
}
~CPlayerManager()
{
delete player_list;
}
void CPlayerManager::AddPlayer(client_id)
{
CPlayer *player = new CPlayer(client_id);
player_list->push_back(player);
}
void *CPlayerManager::GetPlayerInstance(client_id)
{
if(player_list->empty())
{
return NULL;
}
for(std::vector<CPlayer*>::size_type i = 0; i != player_list->size(); i++)
{
int client = player_list->at(i)->GetClientId();
if(client_id == client)
{
return player_list->at(i);
}
}
return NULL;
}
Original game functions use a client indexes as arguments and return values, so i need to obtain player instances from client indexes all the time. The problem is in the GetPlayerInstance function. This function might be called when NO client has been yet initialized and stored by the CPlayerManager instance, so we might have an empty vector.
Anytime the GetPlayerInstance function is called when the vector is empty, the entire game server crashes. I've been debugging a bit, and i noticed that the program crashes right in:
//Code reaches here
if(player_list->empty())
{
//code does not reach here
return NULL;
}
Doing bool empty = player_list->empty()) works until i evaluate empty on the if statement.
What could be causing this strange crash?
Your CPlayerManager class has no copy assignment operator or copy constructor. So if you ever copy it, deleting one instance will delete the other instance's vector, leading to disaster. (Follow the rule of three.)
Really, this code should be nuked from orbit. You have no need for a pointer to a vector nor do you need a vector of pointers. Both of these things are just asking for trouble.
Related
I have created a StateNode class which is not making a copy of itself when I try to pass by value. During the running of my algorithm I receive a 'segmentation fault' error, which is been caused by the StateNode class, once it is being passed to the recursive function. However the 'segmentation fault' only occurs on about the 10,000 call, making me think it is some sort of stack overflow. The history node gets to be a size of 10,000. Both this and the size attribute, are continuously increasing. Making it appear that all function calls are modifying the same data rather than making copies and keeping local data. As the both attributes reach a size impossible with data not been copied correctly.
Here is a template of its declaration and constructors
// State node, contains all current node information
class StateNode {
public:
StateNode();
~StateNode();
StateNode(const StateNode &n2);
void operator = (const StateNode &n2);
....
....
double size = 3.0;
....
vector<double> history;
};
StateNode::StateNode(){
}
StateNode::~StateNode(){
}
StateNode::StateNode(const StateNode &n2){
size = n2.size;
....
....
history = n2.history;
....
}
void StateNode::operator = (const StateNode &n2){
size = n2.size;
....
....
history = n2.history;
....
}
Here is a template of the algorithm. It is a basic recursive algorithm. To confirm I have checked to ensure it is not in an infinite loop. I think the problem is to do with my constructors. And I may need to use an initialization list? But I am unsure if this is the correct step.
double transverse(StateNode node){
if (......){
return value;
}
if (......){
return transverser(node);
}
if (.....){
return transverser(node);
}
else{
node2 = node;
return transverse(node2);
}
}
First of all you should read on the Rule of zero. As you don't manually manage any resource you shouldn't have any user defined copy ctor, copy assign and destructor.
I see nothing wrong with your code. The seg fault is probably caused by the high level of recursion deep.
I have the following situation.
FooClass* fooPointer = new FooClass();
int main() {
while (/*logic*/) {
if (fooPointer) {
// some logic
}
}
}
class FooClass {
void fooClass::fooMethod() {
if (/*logic*/) {
//logic
delete this;
}
}
}
So I am basically deleting the object. However on the next iteration It still enters the if statement in the main method (
if (fooPointer) {
// some logic
}
).
Why doesn't it recognize that the object has already been deleted with the null check?
Calling delete on an object usually is doing two things:
It calls the destructor
It frees the memory of the object
It does not set anything to null nor does it change the value of pointers in any other means. That's why your check doesn't work.
So if you want to go this way, you somehow have to null your pointer yourself.
I am editing some code of an open source game and normally the code doesn't directly access the player or creature class; however its parameter Cylinder is at the top of the food chain when it comes to everything.
My question is should I be deleting all these pointers or setting them to NULL after I am done with them?
Here is the code I've written; it works fine but I don't want to crash the server over an issue such as a dangling pointer (still a bit new to C++).
bool Game::removeMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/)
{
if (cylinder == nullptr) {
return false;
}
if (money == 0) {
return true;
}
if (Creature *creature = cylinder->getCreature()) {
if (Player *player = creature->getPlayer()) {
uint64_t cash = player->getBankBalance();
if (cash < money) {
return false;
}
player->setBankBalance(cash - money);
}
}
return true;
}
void Game::addMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/)
{
if (Creature *creature = cylinder->getCreature()) {
if (Player *player = creature->getPlayer()) {
player->setBankBalance(player->getBankBalance() + money);
}
}
}
In general (and unless the documentation says otherwise), don't delete objects if you are passed a pointer. Assume that you are not being given ownership of the object.
Modern C++ helps you avoid needing to know whether you are being given ownership: you may be given a std::shared_ptr<Cylinder> or a std::unique_ptr<Cylinder> - either way, deletion is handled for you when the smart pointer goes out of scope. But often, you have to work with a library that doesn't give you such reassurance.
There's no need to null out any pointers used within a small scope (e.g. a function). If you keep pointer variables around for longer (in a member variable, perhaps), then it may help prevent accidents if you do so. As C++ is not a garbage-collected language, there's no benefit from nulling pointers that are about to go out of scope.
delete is only required if there is a call to new when you obtain the Cylinder object from the game. There probably isn't, but you need to check the code.
Setting to NULL is something that you do if the object pointed to has been (or is at risk of getting) deleted. This is only to ensure that the invalid pointer cannot be accidentally used some time later.
I would like to know how delete works?
In main function I have deleted the cfact object. But still the cfact->Hello() works instead of throwing an error.
While debugging I found while delete happens, cfact releases the memory. as soon as factory* c2fact = newfun.Newfun("c2_fact"); line executes cfact gets some memory location.
class factory{
public:
virtual void Hello() = 0;
};
class c_fact: public factory
{
public:
void Hello(){
cout << "class c_fact: public factory"<<endl;
}
};
class c2_fact: public factory
{
public:
void Hello(){
cout << "class c2_fact: public factory"<<endl;
}
};
class callFun{
public:
virtual factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else
{return new c2_fact;}
}
};
class newFun:public callFun{
public:
factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else if (data == "c2_fact")
{return new c2_fact;}
}
};
int main()
{
newFun newfun;
factory* cfact = newfun.Newfun("c_fact");
delete cfact; //Deleted the instance
factory* c2fact = newfun.Newfun("c2_fact");
cfact->Hello();//Still it prints the output
c2fact->Hello();
system("pause");
return 0;
}
delete doesn't actually invalidate what it points to. It just tells the OS that the memory can be used for something else and that the program doesn't need it anymore.
If it not overwritten by other data your data will still be in memory and will still be accessible. This is a cause of many bugs that go undetected during development phase and later show up.
The fact that is is working now doesn't mean it will always work. For example if you move the code to another machine or if you restart your computer the code might segfault.
It is always a good practice to set pointers to NULL after delete. Or even better use smart pointers.
This is undefined behavior, most likely this works because the method Hello is not using any of the classes variables and thus is not using the this pointer. Trying outputting this in Hello and you should see an invalid pointer after the call to delete:
std::cout << std::hex << this << << std::endl ;
In my test case it comes back as 0 after delete
Dereferencing a deleted pointer is undefined behaviour. That means anything can happen, including the program appearing to "work". You cannot rely on any such behaviour.
When you delete the memory it is released. however, the content is usually not changed, so anything that is written in that memory is still there after the delete, but you don't know how long it will stay, as other functions can grab it and overwrite it with their own data.
On some compilers, when compiling in debug mode, the memory is marked, so that you can detect such errors as you did by reusing the deleted pointer. However that is not necessarily the default. So you should never reuse a pointer that was deleted.
Sorry I can't comment...
I compiled your code and you can observe that c2fact replaces the cfact you just destroyed (the output is
class c2_fact: public factory
class c2_fact: public factory
)
BTW if you put "cfact->Hello();" before you create your c2fact, the program may crash (which is what you seem to wish) because the mem blocks are not affected to any object. Note that this behavior may change depending on the memory monitoring and other running processes.
I have a strange problem in C++. An address of a Boolean gets "destroyed" but it doesn't get touched. I know that there are better ways to accomplish what I try to do, but I want to know what I do wrong.
I have a main class; this main class contains a vector of another class. There is a strange problem when a new instance gets created of this object.
This is how my code works:
There will start a thread when the constructor gets called of the β2ndβ object. This thread gets as Parameter a struct. This is the struct:
struct KeyPressData
{
vector<bool> *AutoPressStatus;
vector<int> *AutoPressTime;
bool * Destroy;
bool * Ready;
};
The struct gets filled in the constructor:
MultiBoxClient::MultiBoxClient()
{
//init data
DestroyThread = new bool;
ReadyThread = new bool;
AutoThreadData = new KeyPressData;
//Reseting data
*DestroyThread = false;
*ReadyThread = false;
//KeyPressData configurating
AutoThreadData->AutoPressStatus = &AutoPressStatus;
AutoThreadData->AutoPressTime = &AutoPressTime;
AutoThreadData->Destroy = DestroyThread;
AutoThreadData->Ready = ReadyThread;
//Start the keypress thread
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)AutoKeyThread,AutoThreadData,NULL,NULL);
}
This is the defenition of MultiBoxClient:
class MultiBoxClient
{
private:
HWND ClientHandle;
vector<bool> KeyPresses;
vector<bool> AutoPressStatus;
vector<int> AutoPressTime;
KeyPressData * AutoThreadData;
bool * DestroyThread;
bool * ReadyThread;
public:
MultiBoxClient();
MultiBoxClient(HWND Handle);
~MultiBoxClient();
void EditClient(HWND Handle);
void SendKeypress(vector<bool> KeyStatus);
void SendKeyCombination(unsigned int id);
void AutoCast(int Key,unsigned int Time,bool status);
bool IsAlive();
};
MultiBoxClient is created this way:
int main()
{
MultiboxControler * MainControler = new MultiboxControler;
while(true)
{
Sleep(1000);
}
delete MainControler;
return false;
}
As long as the constructor is running will the program run fine. But when the constructor closes the address of the AutoThreadData->Destroy will get corrupted. The program will crash when I call the value of the pointer.
β
void WINAPI AutoKeyThread(void * ThreadData)
{
KeyPressData * AutoThreadData = (KeyPressData*)ThreadData;
while(true)
{
if(*AutoThreadData->Destroy == true) //CRASH
{
*AutoThreadData->Ready = true;
return;
}
Sleep(100);
}
}
What did I test:
I logged the address of the AutoThreadData and the AutoThreadData->Destroy when the constrcutor is running and clossed; the AutoThreadData address is equal to AutoThreadData when the constructor is closed. So there is no problem here.
The address of AutoThreadData->Destroy gets destroyed when the constructor is closed. But how can this happen? The Boolean is on the heap and the KeyPressData struct (AutoThreadData) is on the heap.
Destroy before: 00A85328
Destroy after: FEEEFEEE
Can someone maby explain why this crash?
I know that I can send a pointer to my class to the thread. But I want to know what goes wrong here. That way I can learn from my mistakes.
Could someone help me with this problem?
I guess that you made a mistake with the vector, use a class pointer, instead of the class itself, like this:
vector<class*> //instead of vector<class>
0xFEEEFEEE is an indication of freed memory. That is, you AutoThreadData was deleted, and it was not on your worker thread which is in endless loop. So, it has to be your main thread and perhaps destructor, which you did not show.
Whereever you destroy/free your KeyPressData instance, comment this out or set a breakpoint there to find out where it is taking place.