BulkLoading the R* tree with spatialindex library - c++

After successfully building the R* tree with spatial library inserting records one-by-one 2.5 million of times, I was trying to create the R* tree with bulkloading. I implemented the DBStream class to iteratively give the data to the BulkLoader. Essentially, it invokes the following method and prepared a Data (d variable in the code) object for the Bulkloader:
void DBStream::retrieveTuple() {
if (query.next()) {
hasNextBool = true;
int gid = query.value(0).toInt();
// allocate memory for bounding box
// this streets[gid].first returns bbox[4]
double* bbox = streets[gid].first;
// filling the bounding box values
bbox[0] = query.value(1).toDouble();
bbox[1] = query.value(2).toDouble();
bbox[2] = query.value(3).toDouble();
bbox[3] = query.value(4).toDouble();
rowId++;
r = new SpatialIndex::Region();
d = new SpatialIndex::RTree::Data((size_t) 0, (byte*) 0, *r, gid);
r->m_dimension = 2;
d->m_pData = 0;
d->m_dataLength = 0;
r->m_pLow = bbox;
r->m_pHigh = bbox + 2;
d->m_id = gid;
} else {
d = 0;
hasNextBool = false;
cout << "stream is finished d:" << d << endl;
}
}
I initialize the DBStream object and invoke the bulk loading in the following way:
// creating a main memory RTree
memStorage = StorageManager::createNewMemoryStorageManager();
size_t capacity = 1000;
bool bWriteThrough = false;
fileInMem = StorageManager
::createNewRandomEvictionsBuffer(*memStorage, capacity, bWriteThrough);
double fillFactor = 0.7;
size_t indexCapacity = 100;
size_t leafCapacity = 100;
size_t dimension = 2;
RTree::RTreeVariant rv = RTree::RV_RSTAR;
DBStream dstream();
tree = RTree::createAndBulkLoadNewRTree(SpatialIndex::RTree::BLM_STR, dstream,
*fileInMem,
fillFactor, indexCapacity,
leafCapacity, dimension, rv, indexIdentifier);
cout << "BulkLoading done" << endl;
Bulk loading calls my next() and hasNext() functions, retrieved my data, sorts it and then seg faults in the building phase. Any clues way? Yeah, the error is:
RTree::BulkLoader: Building level 0
terminate called after throwing an instance of 'Tools::IllegalArgumentException'

The problem supposedly lies in the memory allocation and a few bugs in the code (somewhat related to memory allocation too). Firstly one needs to properly assign the properties of the Data variable:
memcpy(data->m_region.m_pLow, bbox, 2 * sizeof(double));
memcpy(data->m_region.m_pHigh, bbox + 2, 2 * sizeof(double));
data->m_id = gid;
Second (and most importantly) getNext must return a new object with all the values:
RTree::Data *p = new RTree::Data(returnData->m_dataLength, returnData->m_pData,
returnData->m_region, returnData->m_id);
return returnData;
de-allocation of memory is done by RTree so no care is needed to be taken here.

Related

C++ double free or corruption (out)

Here is my code:
#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
std::vector<AccountsStruct> accounts;
AccountsStruct accountsStruct;
for (Row row : res.fetchAll()){
accountsStruct.id = row[0].get<int>();
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
accountsStruct.state = row[4].get<int>();
accountsStruct.name = row[5].get<std::string>();
accountsStruct.lastname = row[6].get<std::string>();
accountsStruct.country = row[7].get<std::string>();
accountsStruct.dob_month = row[8].get<int>();
accountsStruct.dob_day = row[9].get<int>();
accountsStruct.dob_year = row[10].get<int>();
accountsStruct.balance = row[11].get<double>();
accountsStruct.created_at = row[12].get<std::string>();
accountsStruct.updated_at = row[13].get<std::string>();
accountsStruct.account_role = row[15].get<int>();
accountsStruct.rank = row[16].get<int>();
accountsStruct.playerRole = row[17].get<int>();
Data.emplace_back(&accountsStruct);
}
std::cout << "SIZE: " << Data.size() << std::endl;
}
Data is std::vector<std::unique_ptr<DataStruct>> Data;.
To add into the vector I call Data.emplace_back(&accountsStruct); which leads me to the following output:
SIZE: 2
double free or corruption (out)
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
I am sure this line Data.emplace_back(&accountsStruct); is causing the issue. Why? How can I fix it?
You're trying to free memory not allocated with new (stack memory, to be precise).
std::vector<std::unique_ptr<DataStruct>> Data;
AccountsStruct accountsStruct; // <-- a stack variable
Data.emplace_back(&accountsStruct); // <-- an instance of unique_ptr is created using the address of accountsStruct
So when Data is destroyed, unique_ptr calls delete on that pointer (not good!!).
I can think of 2 possible solutions:
Allocate accountsStruct on the heap using std::make_unique:
for (auto& row : res.fetchAll()) {
Data.emplace_back(std::make_unique<AccountsStruct>()); // allocate a new instance on the heap
AccountsStruct& accountsStruct = *Data.back(); // get a reference to that instance
accountsStruct.id = row[0].get<int>(); // fill it normally ...
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
. . .
Simplify Data to store by-value: std::vector<DataStruct> Data;
for (auto& row : res.fetchAll()) {
Data.emplace_back(); // allocates a new instance of AccountsStruct in-place
AccountsStruct& accountsStruct = Data.back(); // get a reference to that instance
accountsStruct.id = row[0].get<int>(); // fill it normally ...
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
. . .
Data should contain a std::unique_ptr<AccountsStruct>. I'm afraid, unique_ptr can't be created from AccountsStruct.
So, create struct dynamically, fills by data, create unique_ptr from pointer and add it to vector.
The problem in your code is that you provide an address of a local variable to the constructor of std::unique_ptr.
I assume that Data is std::vector<std::unique_ptr<AccountsStruct>> If AccountsStruct has constructor with no arguments, you can try this:
#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
std::vector<AccountsStruct> accounts;
// create an instance in the vector and get a reference to it
// auto will be std::unique_ptr<AccountsStruct>&;
auto &accountsStruct = Data.emplace_back();
// work with that reference
for (Row row : res.fetchAll()){
accountsStruct->id = row[0].get<int>();
accountsStruct->email = row[1].get<std::string>();
accountsStruct->warTag = row[2].get<std::string>();
accountsStruct->state = row[4].get<int>();
accountsStruct->name = row[5].get<std::string>();
accountsStruct->lastname = row[6].get<std::string>();
accountsStruct->country = row[7].get<std::string>();
accountsStruct->dob_month = row[8].get<int>();
accountsStruct->dob_day = row[9].get<int>();
accountsStruct->dob_year = row[10].get<int>();
accountsStruct->balance = row[11].get<double>();
accountsStruct->created_at = row[12].get<std::string>();
accountsStruct->updated_at = row[13].get<std::string>();
accountsStruct->account_role = row[15].get<int>();
accountsStruct->rank = row[16].get<int>();
accountsStruct->playerRole = row[17].get<int>();
}
std::cout << "SIZE: " << Data.size() << std::endl;
}
If AccountsStruct is derived from DataStruct you can use:
data.emplace_back(std::make_unique<AccountData>());

'std::bad_alloc' when trying to delete priority_queue elements C++

When returning a ship to the port, speed becomes 0.0 and user inputs shield and fuel.
–If fuel is 0.0, the ship gets destroyed
–Ships still in the priority_queue take 10 shield damage and lose 15 fuel
–If shield or fuel become less than 0.0, the ship gets destroyed
Trying to implement these instructions for my final project. The ships are pointer types and they are in a priority queue named 'battlefield'. The ships also exist in a list of pointers called 'port'. I'm trying to destroy the ships that receive lethal damage but when I try to show them, the Qt program crashes and I get bad_alloc error. This is the last thing I have to do for my project :(
Important code blocks from various files:
I already tried to delete the ships from the port, also tried directly deleting them from the port but the priority_queue gets messed up.
class Civilization {
string name;
int x;
int y;
list<Villager> villagers;
list<Ship*> port;
priority_queue<Ship*, vector<Ship*>, Ship::comp> battle;
}
void Civilization::damageShips()
{
priority_queue<Ship*, vector<Ship*>, Ship::comp> copy = battle;
Ship *s = battle.top();
s->setSpeed(0.0);
while(!copy.empty()) {
Ship *s = copy.top();
s->setShield(s->getShield() - 10);
s->setFuel(s->getFuel() - 15);
copy.pop();
}
priority_queue<Ship*, vector<Ship*>, Ship::comp> temp;
while(!copy.empty()) {
Ship *s = copy.top();
string id = s->getId();
if (s->getShield() > 0 && s->getFuel() > 0) {
temp.push(s);
} else
deleteShip(id);
copy.pop();
}
battle = temp;
battle.pop();
}
void battlefielddisplay::setCivilization(Civilization *civilizaition)
{
size_t size = civilizaition->battlefieldSize();
ui->battlefield_table->setRowCount(int(size));
Civilization &c = *civilizaition;
priority_queue<Ship*, vector<Ship*>, Ship::comp> copy = c.getBattlefield();
int cnt = 0;
while(!copy.empty()) {
Ship *s = copy.top();
QString id = QString::fromStdString(s->getId());
QString fuel = QString::number(s->getFuel());
QString speed = QString::number(s->getSpeed());
QString shield = QString::number(s->getShield());
QString warriors = QString::number(s->size());
QTableWidgetItem *idItem = new QTableWidgetItem(id);
QTableWidgetItem *fuelItem = new QTableWidgetItem(fuel);
QTableWidgetItem *speedItem = new QTableWidgetItem(speed);
QTableWidgetItem *shieldItem = new QTableWidgetItem(shield);
QTableWidgetItem *warriorsItem = new QTableWidgetItem(warriors);
ui->battlefield_table->setItem(cnt, 0, idItem);
ui->battlefield_table->setItem(cnt, 1, fuelItem);
ui->battlefield_table->setItem(cnt, 2, speedItem);
ui->battlefield_table->setItem(cnt, 3, shieldItem);
ui->battlefield_table->setItem(cnt, 4, warriorsItem);
cnt++;
copy.pop();
}
}
void MainWindow::on_battle_remove_ship_clicked()
{
if (flag) {
Civilization* c = videogame.searchCivilization(ui->civilization_search_input->text().toStdString());
double shield = ui->shield_battle_remove->value();
double fuel = ui->fuel_battle_remove->value();
Ship *s = c->getBattleShip();
s->setSpeed(0.0);
s->setShield(shield);
s->setFuel(fuel);
c->damageShips();
qDebug() << "[✔]" << "Removed ship from battlefield";
} else
QMessageBox::information(this, "Error", "Civilization not found");
}
bool Civilization::deleteShip(string &id)
{
bool found = false;
for(size_t i(0); i < shipSize(); ++i) {
auto it = port.begin();
advance(it, i);
auto x = *it;
if (x->getId() == id) {
port.erase(it);
delete x;
--i;
found = true;
}
}
return found;
}
The main problem I see is that you delete the objects without removing the pointers from the container. You are iterating the same container multiple times and trying to access the deleted objects.
An additional problem is that you have multiple copies of the same queue so even removing the pointer from the main container may cause problems.
Try to reconsider the algorithm paying special attention to the life time of the objects. For example you may have a lazy deletion: instead of deleting just mark the objects as those that shall be deleted later. You may have a cleanup at the end of your function.

Relocating memory for variable array size

Let's say we have got an array of villages. Each village is unique with regards to the array. A village can have multiple stores. The problem is that you only have limited (dynamic) memory and cannot recklessly initialise memory that you will not use. Therefore, If you create a new store in a village, you will need to relocate your village to a different place in the memory since the size of the village has grown. If you add a new village, you will have to relocate as well in order to accumulate for the extra size.
The problem is that you cannot simply use the following:
pVillage = (Village *)realloc( pVillage, ++MAX_VILLAGE * sizeof(Village));
This is because you will create memory for x villages containing 1 store per village. Since it could be the case that existing villages have multiple stores, the memory allocation will fail and could possibly overwrite memory which you shouldn't touch!
My example c++ code is as such:
class Store
{
char* m_pStoreName;
int m_nAmountOfProducts;
public:
Store(char* name, int number);
Store();
};
Store::Store(char* name, int number)
{
char *m_pStoreName = new char[10];
strcpy( m_pStoreName, name );
m_nAmountOfProducts = number;
}
Store::Store()
{
}
int nMaxStore = 1;
class Village
{
int m_nAmountOfStores;
Store *m_pStoreDb = (Store *)malloc( nMaxStore * sizeof(Store) );
public:
char* m_pVillageName;
Village(char* name);
Village();
addStore(Store* st);
};
Village::Village(char* name)
{
char *m_pVillageName = new char[10];
strcpy(m_pVillageName, name);
m_nAmountOfStores = 0;
}
Village::Village()
{
}
Village::addStore(Store* st)
{
if ( m_nAmountOfStores == nMaxStore )
{
//Need more memory
m_pStoreDb = (Store *)realloc( m_pStoreDb, ++nMaxStore * sizeof(Store) ); //Realocate and copy memory
}
//Add to db
*( m_pStoreDb + m_nAmountOfStores++ ) = *st;
}
int nAmountVillages = 0;
int nMaxVillages = 1;
Village *pVillageDB = (Village *)malloc( nMaxVillages * sizeof(Village) );
int main()
{
addNewVillage("Los Angeles", new Store("Store 1", 20));
addNewVillage("San Fransisco", new Store("Store 1", 10 ));
addNewVillage("New York", new Store("Store 1", 15));
addNewVillage("Los Angeles", new Store("Store 2", 12));
addNewVillage("Los Angeles", new Store("Store 3", 22));
addNewVillage("Amsterdam", new Store("Store 1", 212));
addNewVillage("Los Angeles", new Store("Store 4", 2));
return 0;
}
void addNewVillage(char* villageName, Store *store)
{
for ( int x = 0; x < nAmountVillages; x++ )
{
Village *pVil = (pVillageDB + x);
if ( !strcmp(pVil->m_pVillageName, villageName) )
{
//Village found, now add store
pVil->addStore( store );
return;
}
}
//Village appears to be new, add new one after expanding memory
if ( nAmountVillages == nMaxVillages )
{
//Need more memory
pVillageDB = (Village *)realloc( pVillageDB, ++nMaxVillages * sizeof(Village) ); //Realocate and copy memory
}
//Create new village and add store to village
Village *pNewVil = new Village( villageName );
pNewVil->addStore( store );
//Add village to DB
(pVillageDB + nAmountVillages++ ) = pNewVil;
}
My problem, question is:
What is the correct way to dynamically enlarge an array of custom
objects if not all objects have the same size, or if an existing
object in this array grows in size (new stores in a village)?
I have previously created the following function:
int Village::calculateStoreSize()
{
int nSize = 0;
for ( int x = 0; x < m_nAmountOfStores; x++ )
{
Store *pStore = ( m_pStoreDb + x );
nSize += sizeof(*pStore);
}
return nSize;
}
I tried using it in the following function to relocate the store array in a village object:
m_pStoreDb = (Store *)realloc( m_pStoreDb, Village::calculateStoreSize() + sizeof(Store) );
Unfortunately, when adding a new village, everything goes wrong with memory!
There are two types of arrays in C/C++: Static and Dynamic.
Unfortunately even though the latter one suggests that the size can be "easily adjusted" via calls like realloc(), the truth is, always reallocating all the objects of an array just to increase the size by 1 is tedious and should thus be avoided. However there is a workaround!
If I understand your question correctly, you want to dynamically allocate memory for objects of varying size. The casual way to do so is via linked lists. The most basic linked list would look something like this:
struct store {
char* name;
int products;
store* next;
};
class MyLinkedList {
private:
store* first;
public:
//Constructor
MyLinkedList();
//Destructor: iterate through the list and call delete on all elements.
~MyLinkedList();
void Add(const char* name, int products) {
if(this->first == NULL) {
store* new_store = new store;
new_store->name = new char[30];
strcpy(new_store->name, name);
new_store->products = products;
new_store->next = NULL;
this->first = new_store;
} else {
store* iter = this->first;
while(iter->next != NULL) {
iter = iter->next;
}
//Now iter points at the last element within the linked list.
store* new_store = new store;
new_store->name = new char[30];
strcpy(new_store->name, name);
new_store->products = products;
new_store->next = NULL;
iter->next = new_store;
}
}
//...
};
If you don't want to implement your own, you should have a look at the Standard Template Library's std::vector.
See Stackoverflow - Linked Lists in C++ or Wikipedia - Linked Lists for more detail on linked lists, or to get a good description of the STL's std::vector see cpluslus.com - std::vector.
Hope I could help, cheers!
lindebear
PS: You can also nest linked lists, see here.

std::list copy to std::vector skipping elements

I've run across a rather bizarre exception while running C++ code in my objective-C application. I'm using libxml2 to read an XSD file. I then store the relevant tags as instances of the Tag class in an std::list. I then copy this list into an std::vector using an iterator on the list. However, every now and then some elements of the list aren't copied to the vector. Any help would be greatly appreciated.
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
std::list<Tag>::iterator it = XSDFile::tagsList.begin();
//result: length list = 94, length vector = 0
/*
for(;it!=XSDFile::tagsList.end();++it)
{
XSDFile::tags.push_back(*it); //BAD_ACCESS code 1 . . very bizarre . . . . 25
}
*/
std::copy (XSDFile::tagsList.begin(), XSDFile::tagsList.end(), std::back_inserter (XSDFile::tags));
printf("\n Num tags in vector = %lu\n", XSDFile::tags.size());
if (XSDFile::tagsList.size() != XSDFile::tags.size())
{
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
//result: length list = 94, length vector = 83
}
I've found the problem. The memory was corrupted causing the std::list to become corrupted during the parsing of the XSD. I parse the XSD using a function start_element.
xmlSAXHandler handler = {0};
handler.startElement = start_element;
I used malloc guard in xcode to locate the use of freed memory. It pointed to the line:
std::strcpy(message, (char*)name);
So I removed the malloc (actually commented in the code) and it worked. The std::vector now consistently copies all 94 entries of the list. If anyone has an explanation as to why this worked that would be great.
static void start_element(void * ctx, const xmlChar *name, const xmlChar **atts)
{
// int len = strlen((char*)name);
// char *message = (char*)malloc(len*sizeof(char));
// std::strcpy(message, (char*)name);
if (atts != NULL)
{
// atts[0] = type
// atts[1] = value
// len = strlen((char*)atts[1]);
// char *firstAttr = (char*)malloc(len*sizeof(char));
// std::strcpy(firstAttr, (char*)atts[1]);
if(strcmp((char*)name, "xs:include")==0)
{
XSDFile xsd;
xsd.ReadXSDTypes((char*)atts[1]);
}
else if(strcmp((char*)name, "xs:element")==0)
{
doElement(atts);
}
else if(strcmp((char*)name, "xs:sequence")==0)
{
//set the default values
XSDFile::sequenceMin = XSDFile::sequenceMax = 1;
if (sizeof(atts) == 4)
{
if(strcmp((char*)atts[3],"unbounded")==0)
XSDFile::sequenceMax = -1;
int i = 0;
while(atts[i] != NULL)
{
//atts[i] = name
//atts[i+i] = value
std::string name((char*)atts[i]);
std::string value((char*)atts[i+1]);
if(name=="minOccurs")
XSDFile::sequenceMin = (atoi(value.c_str()));
else if(name=="maxOccurs")
XSDFile::sequenceMax = (atoi(value.c_str()));
i += 2;
}
}
}
}
//free(message);
}

Creating object in C++ , what if already constructed?

I am still new to c++. I want to read in messages from several sources. Each source will begin data messages with a 4 char ID. Each will also have several data messages. No one message has all of the info I want from the device. So if I create an object with the ID as the object name, the next time a message is received, will the object be updated or completely reconstructed? Is there a way to check if the object is already constructed before calling it in the code?
class Channels{
public:
INT8U systemID; //0x01 Glonass, 0x02 GPS
INT8U satID;
INT8U GlonassNumber;
INT8U SNR; //signal to noise ratio
FP64 carrierPhase; //cylces
FP64 psuedoRange; //milliseconds
FP64 doppler; //HZ cycles
float tropDelay; //meters
float ionoDelay; //meters
};
class BaseStation{
public:
Channels channel[32]; //each channel object has all channel class variables in it
int numberSatelitesTracked;
FP64 timeUTC;
INT16U week;
FP64 GPStoUTCoffset;
FP64 GLOtoUTCoffset;
INT8S recieverTimeOffset;
FP64 posX; //geocentric coordinates in meters
FP64 posY;
FP64 posZ;
FP64 rmsX; //expected root mean square error of coordinates
FP64 rmsY;
FP64 rmsZ;
};
if( check == SOCKET_ERROR){
if( WSAGetLastError() != WSAEWOULDBLOCK){
printf("base station client recieve failed with error %d \n", WSAGetLastError());
FreeSocketInformation(i); //shuts down client socket if no data
}
continue;
}
else{
//recieve bytes into array
memcpy(recvArray, SocketInfo->DataBuf.buf, SocketInfo->RecvBytes +1);
//print recieved bytes on screen
printf("%s \n", SocketInfo->DataBuf.buf);
//first 4 bytes in message are base ID
cBuffer[0] = recvArray[0];
cBuffer[1] = recvArray[1];
cBuffer[2] = recvArray[2];
cBuffer[3] = recvArray[3];
baseID = cBuffer;
//create object with 4 char name
BaseStation baseID;
//test message identity and sort data
if(recvArray[4] == 0x10 && recvArray[5] == 0xF5){
baseID.timeUTC = combine64(recvArray[6]);
baseID.week = combine16u(recvArray[14]);
baseID.GPStoUTCoffset = combine64(recvArray[16]);
baseID.GLOtoUTCoffset = combine64(recvArray[24]);
baseID.recieverTimeOffset = recvArray[32];
int noChannels = (check-30) /30 ;
if (noChannels >= 32){
noChannels = 32;
}
int x = 33;
for(int m = 0; m < noChannels; m++){ //advance reading for channel m
baseID.channel[m].systemID = recvArray[x];
x++;
baseID.channel[m].satID = recvArray[x];
x++;
baseID.channel[m].GlonassNumber = recvArray[x];
x++;
baseID.channel[m].SNR = recvArray[x];
x++;
baseID.channel[m].carrierPhase = combine64(recvArray[x]);
x = x+8;
baseID.channel[m].psuedoRange = combine64(recvArray[x]);
x = x+8;
baseID.channel[m].doppler = combine64(recvArray[x]);
x = x+10;
} //end of for loop to gather F5 sat data
} //end F5 message data
if(recvArray[4] == 0x10 && recvArray[5] == 0xF6){
baseID.posX = combine64(recvArray[6]);
baseID.posY = combine64(recvArray[14]);
baseID.posZ = combine64(recvArray[22]);
baseID.rmsX = combine64(recvArray[30]);
baseID.rmsY = combine64(recvArray[38]);
baseID.rmsZ = combine64(recvArray[46]);
} //end F6 message data
OK so it seems an Array may be the best for me to use. So if I setup 100 base objects and then track the active array elements with a second boolean array, does this look like it should work? (baseID added to the base object)
BaseStation base[100];
boolean baseActive[100];
int baseNumber;
//begin message processing------------------------------------------------------------
//first 4 bytes in message are base ID
cBuffer[0] = recvArray[0];
cBuffer[1] = recvArray[1];
cBuffer[2] = recvArray[2];
cBuffer[3] = recvArray[3];
string name = cBuffer;
//check for existing baseID------------------------------------------------------------
// 100 array positions
//find if base is already in use, create new if not in use
for(baseNumber = 0; base[baseNumber].baseID != name; baseNumber++){
//for statement increases untill it finds baseID == name
if( baseNumber >= 100){ //baseID not currently in use
for(int n=0; baseActive[n] == true; n++){
//for statement increases untill finds a false baseActive
baseNumber = n; //assign baseNumber to the array position
base[baseNumber].baseID = name; //create new baseID
continue;
}
}
}
//check and process message data--------------------------------------------------------
if( base[baseNumber].baseID == name){
baseActive[baseNumber] = true;
//test message identity and sort data
}//end of for loop
//test connection, if no bytes recieved then connection is closed.----------------------
if( SocketInfo->RecvBytes == 0){
FreeSocketInformation(i); //shuts down client socket if no data
continue;
}
}
} //end of read data from socket
}
//need to add a timer to remove non sending bases from the baseActive[] array
C++ is a statically typed language, You need to provide the object name at compile time.
You cannot create an object name at run-time and create object with that name.
As already answered, you can't do so in C++.
However you can solve your problem in other way.
First, you need to bind some ID to some concrete object of structure BaseStation. You can provide this link in two ways - by holding BaseStation objects in associative containter, where keys are ID, or by holding array of BaseStation objects(as far as I can guess you are writing some sort of microcontroller code so std containers can be not available for you).
First approach code example:
//id is 4 char so it can be thought as int on most systems
std::map<int, BaseStation *> baseStations;
int * id = (int*)recvArray; //this hack is for showing how you can convert 4 char to int
//may be in your code (int id = combine32(recvArray[0])) is equvivalent
if(baseStations.find(*id) != baseStations.end()) //checking existance of object with such id
{
//ok, exists, do nothing
}
else
baseStations[*id] = new BaseStation(); //create new
baseStations[*id].timeUTC = combine64(recvArray[6]); //starting copying values
//other values copying
In second situation if you can't use associative containers or can't afford their libs\code because of microcontroller memory lack, you can use just arrays but it's not flexible at all and consumes more operations. Example:
//BaseConnection also holds field names id;
BaseConnection baseConnections[N];
int FindId(int id); //return index of element in baseConnections array with this id
BaseConnection * workingConnection = &baseConnections[FindId(combine32(recvArray[0]))];
workingConnection->timeUTC = combine64(recvArray[6]); //starting copying values
//other values copying