For hours now I've been trying to work out to how I can assign dynamic memory to a certain playerid, when they join a server, and destroy it when they leave.
I've tried numerous things, I've tried making an array of pointers... which would allow me to access the information with the player ID using the pointer and array position:
int *pInfo[MAX_PLAYERS]; // Global
//Function Local
CPlayers p;
pInfo[playerid] = p;
Which doesn't work, it tells me it cannot convert the class initialisation to a memory pointer.
I tried the same thing, with this line instead:
std::unique_ptr<CPlayers> pInfo[playerid];
However it needs a constant expression where playerid is, this means I cannot do this unless I know what the player ID is and enter it directly... which is impossible as I won't know until they client tries to connect.
Does anyone have a solution that will allow me to make memory dynamically, and have this memory accessible via the playerid. Or some other fashion, that me indefinitely use that clients information in game.
As I have ran out of ideas... I can't find anything online. I'm new as well so there may be functions I've over looked.
Thanks.
You can use MAP container to do that. The ideia is that you have 2 values. The first one is the playerID and the second one, a dynamic memory reference, which contains its properties. Following is a simple example to prove the concept.
#include <map>
#include <memory>
#include <iostream>
int main()
{
std::map<int, std::unique_ptr<int>> pinfo;
// Inserting some elements.
pinfo.emplace(1, std::unique_ptr<int>(new int{3}));
pinfo.emplace(800, std::unique_ptr<int>(new int{700}));
for (auto& i: pinfo)
std::cout << "Player " << i.first << ", value " << *i.second.get() << std::endl;
// Deleting. Note that, due unique_ptr, the memory is deallocated automatically
pinfo.erase(1);
std::cout << "Player 1: deleted" << std::endl;
for (auto& i: pinfo)
std::cout << "Player " << i.first << ", value " << *i.second.get() << std::endl;
}
Related
This is most probably trivial and I'm confusing struct allocation and pointers somehow, I apologize for this. I have read answers to similar questions but it didn't help. The code is, as always, way more complicted, this is a reduction from 3000+ lines of code to the gist.
The output I expected was
prep 1
main 1
Instead, I get
prep 1
main 0
This is the code:
#include <iostream>
#include <vector>
using namespace std;
struct Entry
{
vector<int> list;
};
struct Registry
{
vector<Entry> entries;
void prep()
{
Entry* entry = new Entry();
entries.push_back(*entry);
entry->list.push_back(0);
cout << "prep " << entry->list.size() << "\n";
}
};
int main()
{
Registry registry;
registry.prep();
cout << "main " << registry.entries[0].list.size() << "\n";
return 1;
}
You don't store pointers in your vector<Entry> so you should not use new. Instead add a default constructed Entry using emplace_back.
A C++17 approach:
void prep()
{
Entry& entry = entries.emplace_back(); // returns a ref the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
Prior to C++17:
void prep()
{
entries.emplace_back(); // does NOT return a ref the added element
Entry& entry = entries.back(); // obtain a ref to the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
If you do want to create and maniplate your Entry before adding it to entries, you can do that too and then std::move it into entries.
void prep()
{
Entry entry;
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
entries.push_back(std::move(entry)); // moving is a lot cheaper than copying
}
The problem is the order of the prep() function. If you change to push an element into the Element object, and then push it tho the entries vector, the behavior will be the expected.
void prep()
{
Entry* entry = new Entry();
entry->list.push_back(0);
entries.push_back(*entry);
cout << "prep " << entry->list.size() << "\n";
}
This is happening, because you uses a copy in the entries list.
It is also possible to store the pointer of the object therefore you can edit the actual instance after you pushed to the entries vector.
Edit:
As Ted mentioned, there is a memory leak, because the entry created with the new operator never deleted. Another approach could be to use smart pointers (however, in this small example it seems overkill, just use reference)
void prep()
{
std::unique_ptr<Entry> entry = std::make_unique<Entry>();
entry->list.push_back(0);
entries.push_back(*entry.get()); // get the pointer behind unique_ptr, then dereference it
cout << "prep " << entry->list.size() << "\n";
} // unique_ptr freed when gets out of scope
You need to change the implementation of prep():
void prep()
{
Entry entry;
entry.list.push_back(0);
entries.emplace_back(entry);
cout << "prep " << entries.back().list.size() << "\n";
}
There is no need to allocate a Entry on the heap just to make a copy of it.
I wanted to create objects from the class “takeSnapshots” that would learn, upon their instantiation, the name of another object from the class “lock” that they could query later as the state of the “lock” object changes. I can think of multiple ways of letting the object from class “takeSnapshots” know which object it is to query (like including the name of the “lock” object as part of the call to its member functions). But, I thought it better to take care of the relation in the beginning and not worry later if I am calling the correct object combinations.
The included code shows stripped down versions of the two classes and example instantiations created in main.
I have included the outputs on each line following their respective couts.
What I expected was that the constructor of “takeSnapshots” would store away the address of the “lock” object. Then I could use it later when taking a snapshot. You can see that what gets stored away (at least when I use it to get numWheels) is a few addresses off from the address that the “lock” object thinks it has for numWheels.
I am mostly interested in knowing why this code does not work the way I expect, i.e, if this is not a good architectural idea, that is one thing. But with the behavior I’m seeing here, I’m clearly not ready to use pointers in anything complicated and I don’t want to give up on the basic architecture just because of erroneous implementation. Any help would be greatly appreciated.
// simpleTest.cpp : Demonstrates problem I'm having understanding
// pointer to an object.
#include "stdafx.h"
#include<iostream>
using namespace std;
class lock {
public: //Just while I run a test.
int numWheels;
lock(int numW) {
numWheels = numW;
cout << " \n In \"lock\" constuctor, address and value of numWheels
" << &numWheels << " " << numWheels << endl;
} //Values from console: 0034F874 and 4
};
class takeSnapshots {
lock* localLock;
public:
takeSnapshots(lock myLock) {
localLock = &myLock;
cout << " \n In \"takeSnapshots\" constuctor, address and value of
numWheels " << &localLock->numWheels << " "
<< localLock->numWheels << endl;
//Values from console: 0034F794 and 4 "Same value, but not the same
//address as expected from "lock."
}
void takeASnapSnapshot() {
cout << " \n When taking a snapshot, address and value of numWheels
" << &localLock->numWheels << " " << localLock->numWheels <<
endl;
//Values from console: 0034F794 and 2303449 "No longer even the
// same value as expected from "lock."
}
};
int main()
{
lock yourLock(4);
takeSnapshots myShots1(yourLock);
cout << " \n In main (from \"yourLock\"), address and value of
numWheels " << &yourLock.numWheels << " " << yourLock.numWheels <<
endl;
//Values from console: 0034F874 and 4 "Still the same values as set
//in the constructor of "lock."
//Take a picture
myShots1.takeASnapSnapshot();
return 0;
}
Okay so what I am trying to do is add an instance of a class to a specific index of a vector. This index can either be initially non-existent, or be an existing index which has been cleared and is having a new class instance being written to that position.
Below is the function that I have been using to try and write these instances to the vector, and commented at the bottom you can see the other 2 methods that I tried to use, Obviously with push_back only being able to add new vectors at the end.
I have a feeling that assign may only be able to add data to existing elements? And that insert may add a new element and shift the existing elements down instead of overwriting. Just want a bit of clarity on this, as the C++ tutorials have started confusing me.
Also, what would be the correct way to reference/defreference/call the Person vector (in this case being referred to as "allthePeople"), so that it is possible to change its data?
void createnewPerson(int assignID, RECT startingpoint, vector<Person>* allthePeople, int framenumber) {
Person newguy(assignID, startingpoint, framenumber);
std::cout << "New Person ID number: " << newguy.getIDnumber() << std::endl;
std::cout << "New Person Recent Frame: " << newguy.getlastframeseen() << std::endl;
std::cout << "New Person Recent history bottom: " << newguy.getrecenthistory().bottom << std::endl;
int place = assignID - 1;
//This is where I am confused about referencing/dereferencing
allthePeople->assign(allthePeople->begin() + place, newguy);
//allthePeople->insert(place, newguy);
//allthePeople->push_back(newguy);
}
Also just to clarify, "place" is always 1 less than "assignID", because vector positions start at 0, and I simply wanted to start their ID numbers at 1 instead of 0.
-------------EDIT : ADDED IF LOOP THAT SOLVED PROBLEM-----------------
void createnewPerson(int assignID, RECT startingpoint, vector<Person>* allthePeople, int framenumber) {
Person newguy(assignID, startingpoint, framenumber);
std::cout << "New Person ID number: " << newguy.getIDnumber() << std::endl;
std::cout << "New Person Recent Frame: " << newguy.getlastframeseen() << std::endl;
std::cout << "New Person Recent history bottom: " << newguy.getrecenthistory().bottom << std::endl;
int place = assignID - 1;
if (allthePeople->size() > place)
{
//assuming places starts from 1 to vector's size.
(*allthePeople)[place] = newguy;
}
else
{
allthePeople->push_back(newguy);
}
}
assign is meant to replace the full content of a vector.
Assuming that you want to put every person in a specific place. You might then better use operator[] to put the value at the place you want instead of using assign. You need to have the vector with the appropriate size.
if (allthePeople->size() >= place )
{
//assuming places starts from 1 to vector's size.
(*allthePeople)[place - 1] = newguy;
}
I'm developing a application and my idea is store "apps" in files, like executables. Now i have that:
AppWriter.c
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
srand(time(NULL));
for(int i = 0; i < 40; i++)
CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
for(int i = 0; i < CODED.RandomStuff.size(); i++)
std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
std::cout << "Hello i call random function!" << std::endl;
CODED.Functions[0]();
CODED.Functions[1]();
}
void main()
{
CODED.MAIN = PROGRAMMAIN;
CODED.Functions.push_back(RANDOMFUNC);
CODED.Functions.push_back(LOGARRAY);
std::cout << "Testing MAIN" << std::endl;
CODED.MAIN();
FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
fwrite(&CODED,sizeof(CODED),1,file);
fclose(file);
std::cout << "Program writted correctly!" << std::endl;
_sleep(10000);
}
AppReader.c
#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} DUMPED;
void main()
{
FILE *file = fopen("TEST_PROGRAM.TRI","rb+");
fseek(file,0,SEEK_END);
int program_len = ftell(file);
rewind(file);
fread(&DUMPED,sizeof(PROGRAM),1,file);
std::cout
<< "Function array size: " << DUMPED.Functions.size() << std::endl
<< "Random Stuff Array size: " << DUMPED.RandomStuff.size() << std::endl;
DUMPED.MAIN();
}
When i run AppReader the functions dont work(Maybe why std::function it's like void pointers?), but in arrays or if i add variables i can see with debugger the data are storaged correctly (for that i tryed the vector of functions), but whatever doesn't work throw's me error on functional file. ¿Any ideas how i can do that?
This is never going to work. At all. Ever. std::function is a complex type. Binary reads and writes don't work for complex types. They never can. You would have to ask for functions in a pre-defined serializable format, like LLVM IR.
Your problem is that you're storing information about functions that exist in one executable, then trying to run them in a separate executable. Other than that, your code does work, but as DeadMG says, you shouldn't be storing complex types in a file. Here's how I modified your code to prove that your code works if run within a single executable:
#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
std::vector<int> RandomStuff;
std::vector<std::function<void()>> Functions;
std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
srand(time(NULL));
for(int i = 0; i < 40; i++)
CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
for(int i = 0; i < CODED.RandomStuff.size(); i++)
std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
std::cout << "Hello i call random function!" << std::endl;
CODED.Functions[0]();
CODED.Functions[1]();
}
int main()
{
CODED.MAIN = PROGRAMMAIN;
CODED.Functions.push_back(RANDOMFUNC);
CODED.Functions.push_back(LOGARRAY);
std::cout << "Testing MAIN" << std::endl;
CODED.MAIN();
FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
fwrite(&CODED,sizeof(CODED),1,file);
fclose(file);
std::cout << "Program writted correctly!" << std::endl;
// _sleep(10000);
std::cout << "---------------------\n";
file = fopen("TEST_PROGRAM.TRI","rb+");
fseek(file,0,SEEK_END);
int program_len = ftell(file);
rewind(file);
fread(&CODED,sizeof(PROGRAM),1,file);
std::cout
<< "Function array size: " << CODED.Functions.size() << std::endl
<< "Random Stuff Array size: " << CODED.RandomStuff.size() << std::endl;
CODED.MAIN();
}
The problem is not that you're storing complex types via binary read/write, per se. (Although that is a problem, it's not the cause of the problem you posted this question about.) Your problem is that your data structures are storing information about the functions that exist in your 'writer' executable. Those same functions don't even exist in your 'reader' executable, but even if they did, they likely wouldn't be at the same address. Your data structures are storing, via std::function, pointers to the addresses where the functions exist in your 'writer' executable. When you try to call these non-existent functions in your 'reader' executable, your code happily tries to call them but you get a segfault (or whatever error your OS gives) because that's not the start of a valid function in your 'reader' executable.
Now with regard to writing complex types (e.g. std::vector) directly to a file in binary format: Doing so "works" in the sample code above only because the binary copies of the std::vectors have pointers that, once read back in, still point to valid data from the original std::vectors which you wrote out. Note that you didn't write the std::vector's actual data, you only wrote their metadata, which probably includes things like the length of the vector, the amount of memory currently allocated for the vector, and a pointer to the vector's data. When you read that back, the metadata is correct except for one thing: Any pointers in it are pointing to addresses that were valid when you wrote the data, but which may not be valid now. In the case of the sample code above, the pointers end up pointing to the same (still valid) data from the original vectors. But there's still a problem here: You now have more than one std::vector that thinks they own that memory. When one of them is deleted, it will delete the memory that the other vector expects to still exist. And when the other vector is deleted, it will cause a double-delete. That opens the door to all kinds of UB. E.g. that memory could have been allocated for another purpose by that time, and now the 2nd delete will delete that other purpose's memory, or else the memory has NOT been allocated for another purpose and the 2nd delete may corrupt the heap. To fix this, you'd have to serialize out the essence of each vector, rather than their binary representation, and when reading it back in, you'd have to reconstruct an equivalent copy, rather than simply reconstitute a copy from the binary image of the original.
consider this segment of codes:
std::vector<int> vecList;
...populate 3 elements into vecList...
if (!vecList.empty())
{
std::cout << "List count = " << vecList.size() << std::endl;
if (vecList.empty())
{
std::cout << "List is empty" << std::endl;
}
}
my printout is:
List count = 3
List is empty
I did not do anything to "vecList" other than printing out, yet after I printed the size of the vector, the size becomes 0. How is that possible? Any advice is appreciated.
This happened when I am running my build on an Iphone environment.
Thanks
Alexander
Since both std::vector<>empty() and std::vector<>::size() are const member functions and cannot alter the vector's content, the only ways I can see to get that result is by using multiple threads or invoking Undefined Behavior.
Likely candidates are other threads modifying the vector and messing up the vector's internals by buffer overflows and the like.
This
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> vecList;
vecList.push_back(1);
vecList.push_back(2);
vecList.push_back(3);
if (!vecList.empty())
{
std::cout << "List count = " << vecList.size() << std::endl;
if (vecList.empty())
{
std::cout << "List is empty" << std::endl;
}
}
return 0;
}
prints List count = 3 for me. I bet it does the same for you. If so, then there must be something messing things up in the code you don't show.
The only way to find out what it is (other than posting the exact right snippet here and have someone guess right) is to remove all extra code step by step until the problem disappears and then look at the code that triggered it.
You might also want to try Valgrind. Allot of times use of uninitialized values, especially with system calls can cause truly weird behavior.
For instance, a common mistake is the following ( yeah I've made this mistake myself ):
struct timeval tv;
tv.tv_sec = 5;
// This is supposed to sleep for 5 seconds
select(0, NULL,NULL,NULL, &tv);
What's missing? You need to init the second member of the struct as such tv.tv_usec = 0; otherwise it can cause seemingly random errors in completely unrelated sections of the program. Valgrind can help you catch some of these things.
Try debuging your code. It is easy and you will understand when exactly it becomes empty. Though, there is nothing ideal, anyway trust such constructs like STL and other well-kown libraries. In 99.99% cases the cause of the promblem is the programmer.
Looks your code like this? Note the semicolon after the second if.
std::vector<int> vecList;
...populate 3 elements into vecList...
if (!vecList.empty())
{
std::cout << "List count = " << vecList.size() << std::endl;
if (vecList.empty());
{
std::cout << "List is empty" << std::endl;
}
}
If this actually happens, it's most probably another thread modifying the vector.