Preferred way of filling up a C++ vector of structs - c++

Alternative 1, reusing a temporary variable:
Sticker sticker;
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
board.push_back(sticker);
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
board.push_back(sticker);
Alternative 2, scoping the temporary variable:
{
Sticker sticker;
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
board.push_back(sticker);
}
{
Sticker sticker;
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
board.push_back(sticker);
}
Alternative 3, writing straight to the vector memory:
{
board.push_back(Sticker());
Sticker &sticker = board.back();
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
}
{
board.push_back(Sticker());
Sticker &sticker = board.back();
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
}
Which approach do you prefer?
Edit: For the sake of this discussion, assume that the assignments have to be made one by one outside of a constructor

My option - give Sticker a constructor that takes the parameters. then:
board.push_back( Sticker( outline.x, foo.bar, etc. ) );
Edit: Code to illustrate constructor parameter names:
#include <iostream>
using namespace std;
struct S {
int a, b;
S( int a, int b ) : a(a), b(b) {
}
};
int main() {
S s( 1, 2);
cout << s.a << " " << s.b << endl;
}

board.resize(sticker_count);
Then iterate through all the vector and set parameters.

Alternative 1. Why create a scope just for a variable? There is usually an enclosing scope nearby (at the minimum, you should keep your functions/procedures small so that will scope it).
Why? You can create a shorter variable name e.g. st in this case. Since the assignment will be nearby there should be no loss in clarity. Actually it will look simpler and cleaner.
Also, if the vector needs to be dereferenced/accessed from several other levels of indirection, then it will also simplify the code.

How about winforms style:
// Class members
Sticker sticker1;
Sticker sticker2;
Board board;
// Initialization
void InitBoard()
{
sticker1.x = x + foreground.x;
sticker1.y = foreground.y;
sticker1.width = foreground.width;
sticker1.height = foreground.height;
sticker2.x = x + outline.x;
sticker2.y = outline.y;
sticker2.width = outline.width;
sticker2.height = outline.height;
// Add to board
board.push_back(sticker1);
board.push_back(sticker2);
}

Related

Pass array of structs from C++ to GO

I'm trying to get an array of tensorflow box predictions from C++ to golang, but I'm not able to do it no matter what I do. I have a GO program that calls a function that does tensorflow detections in C++ using cgo. This all works and I'm able to get the predictions in C++. The problem is to transfer these predictions into GO as an array of 100 structs that each hold one prediction.
I'm able to set a pointer in GO and use this pointer address to set one struct in C++. The code for this is seen below.
I want to set an array of structs in C++ and retreive this array in GO. I thought it should be easy to just use the same pointer address as earlier and use this as the address for my C++ array. Then I could restore the struct from the pointer in GO. Does anyone have a solution for this?
GO
type PredictResult struct {
Loc [4]float32
Score int
Label int
}
var predictions PredictResult
predictions_ptr := unsafe.Pointer(&predictions)
C.LIB_predict(predictions_ptr)
fmt.Println("GO predictions; ", predictions)
bridge.hpp
struct PredictResult{
float Loc[4];
int64_t Score;
int64_t Label;
};
void LIB_predict(void* predictions);
bridge.cpp
void LIB_predict(void* predictions){
PredictResult *p = (PredictResult*)predictions;
p->Score = 6;
p->Label = 95;
}
Prints:
GO predictions; {[0 0 0 0] 6 95}
Assuming your C function returns the array as PredictResult* and assuming you know the length of the returned array (in the example below I assume 10, but you can replace it by whatever works), this approach should work:
// #include <stdio.h>
// #include <stdlib.h>
//
// typedef struct PredictResult {
// float Loc[4];
// int64_t Score;
// int64_t Label;
// } PredictResult;
//
// PredictResult* getOneResult() {
// PredictResult* p = (PredictResult*)calloc(1, sizeof(PredictResult));
// p->Score = 10;
// p->Label = 99;
// p->Loc[1] = 2.5;
// p->Loc[3] = 3.5;
// return p;
// }
//
// PredictResult* getTenResults() {
// PredictResult* parr = (PredictResult*)calloc(10, sizeof(PredictResult));
// parr[0].Score = 10;
// parr[0].Label = 99;
// parr[0].Loc[1] = 2.5;
// parr[0].Loc[3] = 3.5;
//
// parr[4].Score = 44;
// parr[4].Label = 123;
// parr[4].Loc[1] = 12.25;
// parr[4].Loc[3] = -40.5;
// return parr;
// }
//
//
import "C"
type PredictResult C.struct_PredictResult
func main() {
p := C.getOneResult()
if p == nil {
log.Fatal("got nil")
}
pp := (*PredictResult)(p)
fmt.Println(pp)
parr := C.getTenResults()
if parr == nil {
log.Fatal("got nil")
}
pslice := (*[1 << 28]PredictResult)(unsafe.Pointer(parr))[:10:10]
fmt.Println(pslice)
}
What you'll be most interested in is how the result of getTenResults is converted to a Go slice of the appropriate struct type. This is employing the technique recommended on the Go wiki.
Depending on the exact signature of your C function you may need to write a "bridge" function in the import "C" part to provide the data as convenient to Go, but this is the basic gist of it.
As an alternative, if you wish to allocate the slice on the Go side and pass in a pointer to C to populate, you can do this:
// void PopulateTenResults(void* arr) {
// PredictResult* parr = (PredictResult*)arr;
// parr[1].Score = 210;
// parr[1].Label = 299;
// parr[1].Loc[1] = 22.5;
// parr[1].Loc[3] = 23.5;
//
// parr[8].Score = 344;
// parr[8].Label = 3123;
// parr[8].Loc[1] = 312.25;
// parr[8].Loc[3] = -340.5;
// }
//
//
import "C"
And then in Go do:
prslice := make([]PredictResult, 10)
C.PopulateTenResults(unsafe.Pointer(&prslice[0]))
fmt.Println(prslice)
Of course the hard-coded 10 is just for simplicity here; you could pass the length of arr as a parameter to C.
You can pass a pointer to the first element in a slice and the length of the slice to C++ and treat it like a C-style array.

Is there a way to copy and paste data while simultaneously increasing a number in that data each time?

Basically I have in my program -
team[0].game[2] = loadvar[1];
team[0].game[3] = loadvar[2];
team[0].game[4] = loadvar[3];
team[0].game[5] = loadvar[4];
team[0].game[6] = loadvar[5];
team[0].game[7] = loadvar[6];
team[0].game[8] = loadvar[7];
team[0].game[9] = loadvar[8];
team[0].game[10] = loadvar[9];
team[0].game[11] = loadvar[10];
team[0].game[12] = loadvar[11];
team[1].game[1] = loadvar[13];
team[1].game[2] = loadvar[14];
team[1].game[3] = loadvar[15];
team[1].game[4] = loadvar[16];
team[1].game[5] = loadvar[17];
team[1].game[6] = loadvar[18];
team[1].game[7] = loadvar[19];
team[1].game[8] = loadvar[20];
team[1].game[9] = loadvar[21];
team[1].game[10] = loadvar[22];
team[1].game[11] = loadvar[23];
team[1].game[12] = loadvar[24];
team[2].game[1] = loadvar[26];
team[2].game[2] = loadvar[27];
team[2].game[3] = loadvar[28];
team[2].game[4] = loadvar[29];
team[2].game[5] = loadvar[30];
team[2].game[6] = loadvar[31];
team[2].game[7] = loadvar[32];
team[2].game[8] = loadvar[33];
team[2].game[9] = loadvar[34];
team[2].game[10] = loadvar[35];
team[2].game[11] = loadvar[36];
team[2].game[12] = loadvar[37];
team[3].game[1] = loadvar[39];
team[3].game[2] = loadvar[40];
team[3].game[3] = loadvar[41];
team[3].game[4] = loadvar[42];
team[3].game[5] = loadvar[43];
team[3].game[6] = loadvar[44];
team[3].game[7] = loadvar[45];
team[3].game[8] = loadvar[46];
team[3].game[9] = loadvar[47];
team[3].game[10] = loadvar[48];
team[3].game[11] = loadvar[49];
team[3].game[12] = loadvar[50];
team[4].game[1] = loadvar[52];
team[4].game[2] = loadvar[53];
team[4].game[3] = loadvar[54];
team[4].game[4] = loadvar[55];
team[4].game[5] = loadvar[56];
team[4].game[6] = loadvar[57];
team[4].game[7] = loadvar[58];
team[4].game[8] = loadvar[59];
team[4].game[9] = loadvar[60];
team[4].game[10] = loadvar[61];
team[4].game[11] = loadvar[62];
team[4].game[12] = loadvar[63];
I'm retrieving the data from a text file.
Basically, in the program, I'm having to copy and paste the same thing over and over again, and increasing the array number for the team and loadvar. Is there anyway I can copy and paste it, and it do the number increasing for me?
Simply don't copy + paste, rather use loops to do the incrementing numbers, e.g. for
int v = 1;
for (int t = 0; t < 5; ++t)
{
for (int g = 1; g <= 12; ++g)
{
team[t].game[g] = loadvar[v++];
}
}
I've kept game indexed from 1-12 as in your question, but I suspect you might mean to index from 0-11. Be careful of this common source of bug for beginner programming.
If you really want to copy and paste, you can write something like this
int i = 0;
int j = 2;
int k = 1;
team[i].game[j++] = loadvar[k++];
team[i].game[j++] = loadvar[k++];
and so on. However the shorter and less error prone way would be two nested for loops.

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>());

C++ sharing array elements across modules with const-ness for few fields only

This is sort of a design doubt .
Scenario: I have an array which contain some integer elements . This array is populated by 1 module (.so) in my code base say X. It is then shared to another module say Y (.so) . At run time X module identifies that module Y would need to work on few fields of the array and modify it and that was the reason X shared the array to Y . ( Both these so are consumed into one binary .)
Once Y returns the module X prints the array .
Problem : How can I enforce programatically that module Y does not modify any other array index other than the one identified by X . SInce the whole array is passed between modules i cant make it const as then Y would not be able to change any field . You can say i want to enforce const-ness for few fields identified at run time .
How about this:
template <class T> class CProtectedArray {
private:
T* m_aItems;
unsigned int* m_aMask;
public:
CProtectedArray(int cElem, bool fInitialProtect) : m_aItems(NULL) {
int cbElem = sizeof(T)*cElem;
int cbMask = sizeof(int)*(cElem+31)/32;
m_aItems = (T*)malloc(cbElem + cbMask);
m_aMask = (unsigned int*)(m_aItems + cElem);
memset(m_aItems, 0, cbElem);
memset(m_aMask, fInitialProtect ? -1 : 0, cbMask);
}
~CProtectedArray() {
if (m_aItems)
free(m_aItems);
}
bool IsProtected(int iItem) { return !!(m_aMask[iItem>>5] & (1<<(iItem&31))); }
void Protect(int iItem) { m_aMask[iItem>>5] |= 1<<(iItem&31); }
void UnProtect(int iItem) { m_aMask[iItem>>5] &= ~(1<<(iItem&31)); }
void Set(int iItem, T val) {
if (!IsProtected(iItem))
m_aItems[iItem] = val;
}
};
int main(int argc, char* argv[])
{
CProtectedArray<int> A(100, true);
bool f = A.IsProtected(30); // f = true
A.Set(30, 23); // nothing happens
A.UnProtect(30);
f = A.IsProtected(30); // f = false
A.Set(30, 24); // sets element 30 to 24
A.Protect(30);
f = A.IsProtected(30); // f = true
A.Set(30, 25); // nothing happens
}

BulkLoading the R* tree with spatialindex library

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.