In my code I have something like this:
struct SomeStruct
{
int test1;
int test2;
float test3;
float test4;
};
std::vector<SomeStruct> SomeStructs;
I am looking for a way to get a part of that vector in a continues manner, So that I can access it with a pointer or a c-array.
Suppose I want a pointer to access only the part of the struct that are test2.
I want to pass that part of the vector to a C API, Is it possible?
I'm trying to avoid creating a new std::vector/c-array.
How It look's like in memory(kind of):
No, what you are asking for is impossible. Quick review:
We can clearly see that the test2 entries of the struct are not currently laid out contiguously in memory, because they are just one member of a struct that is contiguous, so clearly the other struct elements sit in between each occurence of test2.
You want them to be contiguous, so you need a different memory layout than you currently have.
You don't want to create a new vector or array, so you are stuck with your current memory layout, which is wrong.
Your options are like so:
Change the variable to be say 4 vectors of variables instead of one vector of structs.
Create a new vector when you need one.
Don't use a C API that requires contiguous memory.
For 3 it is worth noting that some C APIs, notably BLAS, supported "strided" arrays which means that there is a fixed size gap between elements, which would solve this issue for you.
There's no way to access just the contents of each test2 from a pointer or array, because the test2 members are not contiguous in memory even if the structs in the vector are. There's other data in the struct, so you need to skip over that to read each test2.
When you find yourself asking a question like this, try thinking about other data structures you can use that would make the problem easier to solve. For this case, perhaps a std::unordered_map would be a good choice.
std::unordered_map<int,SomeStruct> map;
// make a struct...
map.insert(std::make_pair<int,SomeStruct>(a_struct.test2,a_struct));
// add a bunch more structs...
// get an iterator to all the keys in the map (ie. something like a pointer to all test2 members)
key_iterator = map.begin()
To implement this in an idiomatic manner you will need to roll your own custom iterator that returns that field specifically.
Take a look at c++ how to create iterator over one field of a struct vector
C and C++ interoperability is a vastly different problem. To simplify things you may just want to implement it in C.
If i got you well, i think its possible.
struct SomeStruct
{
int test1;
int test2;
float test3;
float test4;
};
int size = 3;// whatever size
vector<SomeStruct> myStruct(size);
myStruct[0].test1 = 0;
myStruct[1].test1 = 1;
myStruct[2].test1 = 2;
/* myPtest1 will allow you to get the test1 part of myStruct in a
contiguous memory manner*/
int *myPtest1 = new int(myStruct.size());
for(int i = 0; i< myStruct.size(); i++)
myPtest1[i] = myStruct[i].test1;
// for illustration.
cout << myPtest1[0] << endl; // 0
cout << myPtest1[1] << endl; // 1
cout << myPtest1[2] << endl; // 2
You can now pass myPointer to your API, myPointer gives you access to only test1 part of myStruct vector.
you can do same for the rest of the SomeStruct attributes.
If you want to access it in a for loop you can do:
for (const auto& iterator: SomeStructs)
{
const int& test2 = iterator.test2;
// do what you need to do
}
If you need the j-th element:
const int& test2 = SomeStructs[j].test2
In this way you are not making extra copies but you are directly referencing items from vector. Remove const if you need to change the value
Related
I am trying to dynamically allocate memory for a nested struct that happens to be a pointer. I have written some made-up code below to try and illustrate my problem.
These two structs are found in two separate header files, also the code is under one namespace.
Tiles.h
struct Tiles
{
int* m_noOfSections;
int* m_noOfTilesInSecs;
char* m_TileName;
};
// functions omitted
Flooring.h
struct Flooring
{
Tiles* m_Tiles;
int m_noOfTiles;
char* m_FlooringName;
};
void read(Tiles&);
I am working on a function definition for Flooring.h where I have to dynamically allocate an array of Tiles, the size of the array is determined earlier on in this function from user input.
I've tried using the following code but ran into issues:
Flooring.cpp
void read(Flooring&Flr)
{
Tiles* tiles;
tiles = new Tiles[Flr.m_noOfTiles];
for (int i = 0; i < Flr.m_noOfTiles; i++) {
cout << i + 1 << ": ";
read(tiles[i]);
}
}
Note: The read(tiles[i]); [declaration: void read(Tiles&)] function assigns values to the data members of Tiles. I have tested the functions in the Tiles files and they are working as intended. So I have not included the code for those. I believe the issue lies in my Flooring.cpp implementation file.
My expectation is that that the above read function would assign values to:
tiles[i].m_noOfSections, tiles[i].m_noOfTilesinSecs, tiles[i].m_tileName
One of the issues is that I do not have a chance to input tileName, when running the code it skips the part where I would normally input a tileName.
The output would be as follows:
Enter the number of sets of tiles: Enter number of sections: [user is able
to input value here, but not before when asked to enter the number of the set of tiles]
Tiles.cpp
void read(char* tileName)
{
cout << "Enter tile name: ";
read(tileName, 15, "error message") ;
}
The function definition for the read function with three parameters can be found below. This function was pre-defined in this assignment. I have also reviewed the function and I don't see any problems with it, but I will post it regardless if it helps.
void read(char* str, int len, const char* errorMessage)
{
bool ok;
do
{
ok = true;
cin.getline(str, len+1, '\n');
if (cin.fail()) {
cin.clear();
cin.ignore(1000, '\n');
ok = false;
}
}while(!ok && cout << errorMessage);
}
I hope that is enough information, apologies if my formatting isn't adequate, or if my terminology isn't appropriate, I am still quite new to all sorts of programming. Please do let me know if I have forgotten to include some information.
new expression doesn't assign anything, it only value-initializes, if you offer those values, or calls constructor and passes arguments to it.
tiles = new Tiles[Flr.m_noOfTiles];
creates an array of Flr.m_noOfTiles class Tiles with garbage non-nullptr pointers and values. Memory for underlings are not initialized. It could be done, by offering initializer list.
tiles = new Tiles[Flr.m_noOfTiles] { value1, value2, value3 };
You have to allocate memory for every pointer. And when it's not needed, deallocate it, in proper order, from most nested to less nested structure.
This might be not a trivial task depending on operations you need and cause quite a hassle in code. It's the reason why C++ have constructors and destructors. So:
is there reason why you don't use RAII? https://en.cppreference.com/w/cpp/language/raii
Is there reason you don't use standard collections, they already implement RAII.
Is there reason why you don't use smart pointers?
I would suggest using std::vector and std::string, by which the storage of the elements will be managed automatically and thereby manual memory allocations can be avoided and you can concentrate on the implementations.
That means, have a good start with the followings:
#include <iostream>
#include <vector> // std::vector
#include <string> // std::string
struct Tiles
{
std::vector<int> m_noOfSections;
std::vector<int> m_noOfTilesInSecs;
std::string m_TileName;
};
struct Flooring
{
std::vector<Tiles> m_Tiles;
// int m_noOfTiles; // --> obsolete, as you can get the size by calling `m_Tiles.size()`
std::string m_FlooringName;
};
As a side note, in Flooring(maybe also in Tiles) it does look like, you want to map the Tiles's name to a group of Tiles. As per requirements have a look at other data structure like std::pair, std::map, std::multimap, std::unordered_map, std::unordered_multimap
what standard library provides for this scenario.
I have derived from std::vector<int> (I know I shouldn't, but I just wanted to test it). Now I can instantiate it and assign some values:
MyVector v(5);
v[0]=3;
I even can return the value:
cout << v[0];
But how can I access the value(s) if I want to do some operations within the class? Something like:
int func(int a){
return this->[0] + a; // EXAMPLE
}
As stated in the comments under the question:
return (*this)[0] + a; should work. – didierc 5 hours ago
Additionally, since vector lays out memory in a linear fashion (like an array) you can also access the memory which holds the values through a pointer, like so:
int *ptr = &(*this)[0];
// read an integer from the console into the 3rd element of the vector
scanf("%d", ptr + 2);
This can be useful if you have a vector of chars and you need to pass a char* to something like a string function, for example.
Be warned however, vector<bool> does not behave in the same way (the boolean values are stored internally in bitfields, not an array of bools, see http://isocpp.org/blog/2012/11/on-vectorbool).
I'm not very experienced programmer in C++ and I have a problem which I can't resolve. The project on which I'm working is quite big so I can't post here all codes. It is too much code and too much explanation. I write just little part of code, the part which causes me problem, so I hope it is enough. Sorry for the long of my question but I want explain all posted code. Maybe this part of code isn't enough to solve the problem but I want to try it.
First I have a struct called "record":
struct record {
vector<string> dataRow;
vector<string *> keys;
vector<string *> values;
void setDataRow(vector<string> r) {
dataRow = r;
}
}
Some of string data are marked as keys and others as values. I next processing is better for me to have all string data in one vector, so that's the reason why I don't have two vectors of string (vector keys, vector values).
Then I have this:
vector< vector<record> > resultSet;
vector is like data table - set of lines with string data. I need specific count of these tables, therefore vector of vectors of records. The count of tables is optional, so when I set table count I prepare tables by reserve function:
resultSet.reserve(count);
for(unsigned int i = 0; i < count; i++) {
vector<record> vec;
resultSet.push_back(vec);
}
When I want add new record to resultSet I know the number of table to which I need insert record. After resultSet[number].push_back(rec) I need change pointers in vectors "keys" and "values" because push_back() creates new copy of "rec" with values of "dataRow" in other memory addresses, right? So I have this function which does push_back and updates pointers:
void insert(int part, vector<string> & dataRow) {
record r;
r.setDataRow(dataRow);
resultSet[part].push_back(r);
int pos = resultSet.size() - 1; // position of last record
resultSet[part].at(pos).values.clear();
resultSet[part].at(pos).keys.clear();
for(unsigned int i = 0; i < dataRow.size(); i++) {
record * newRec = &resultSet[part].at(pos);
if(isValue(dataRow[i])) {
newRec->values.push_back(&(newRec->dataRow.at(i)));
// control cout...
} else {
newRec->keys.push_back(&(newRec->dataRow.at(i)));
// control cout...
}
}
}
This is working. After push_back in newRec I did control cout of inserted pointers and their referenced values, and everything was ok.
But! After some inserts I call function processData(resultSet), which has to process all data in resultSet. Before implementing processing od data I just wanted print all keys for control to find out if everything is alright. This code:
for(unsigned int i = 0; i < resultSet.size(); i++) {
for(unsigned int j = 0; j < resultSet[i].size(); j++) {
cout << "keys: ";
for(unsigned int k = 0; k < resultSet[i].at(j).keys.size(); k++) {
cout << *resultSet[i].at(j).keys.at(k) << ", ";
}
cout << endl;
}
}
is bad (Same problem with printing values vector of record). It throws exception of Access violation reading. I know that this exception is thrown when I want to read unaccessible memory, right? Please, tell me that I have mistake in code written above because I really don't know why it doesn't work. Before processing resultSet I do nothing with resultSet except some count of inserts.
Thank you for reading and possible answers.
When you add an entry to a std::vector, all existing pointers to elements in that vector should be considered invalid.
Here is the code that is going wrong.
vector<string> dataRow;
vector<string *> keys;
vector<string *> values;
If keys and values point to the strings in dataRow they will become invalid when dataRow grows.
If I have understood your question correctly, the reason for all this is a fundamental misconception in the way vectors behave.
Your code stores pointers in a vector that points to memory locations allocated by another vector. That would be fine if the vectors didn't change.
The reason for this is that a std::vector is a container that makes a guarantee - all the data it contains will be allocated in a contiguous block of memory.
Now, if you insert an element into a vector, it may move memory locations around. Hence, one of the things you should know is that iterators need to be considered invalid when a vector changes. Iterators are sort of a generalized pointer. In other words, pointers to the locations of elements inside a vector become invalid too.
Now, let's say you updated all your pointers, everywhere, when any of the vectors involved changed. You would then be fine. However, you've now got a bit of an uphill battle on your hands.
As you've said in your comments, you're using pointers because you want efficiency. Your struct is essentially a collection of three strings. Instead of using your own struct, typedef a std::tuple (you will need a C++11 compiler) of 3 std::strings.
Finally, when you need to access the data within, do so by const reference and const_iterator unless you need to modify any of it. This will ensure that
You don't have duplication of data
You're making maximum use of the STL, thereby minimizing your own code and the possible bugs
You're relying on algorithms and containers that are already really efficient
You're using the STL in a way it was meant to be used.
Hope this helps.
One possible problem could be in copies of record instances.
struct record
{
vector<string> dataRow;
vector<string *> keys;
vector<string *> values;
};
In fact, default copy constructor and copy operator= do a member-wise copy. This is OK for dataRow field (which is a vector<string>), but this is bad for keys and values fields (since these are vectors of raw pointers, their values are copied, but they point to something wrong).
I'd reconsider your design, e.g. using vector<int> instead of vector<string *> for keys and values fields. The ints stored would be indexes in the dataRow vector.
Another note (not directly related to your problem).
In C++11, when you want to copy something, you may want to pass by value, and move from the value:
void setDataRow(vector<string> r)
{
dataRow = std::move(r);
}
Or just use old C++98/03 style of passing by const ref:
void setDataRow(const vector<string>& r)
{
dataRow = r;
}
How do I add an element to the end of an array dynamically in C++?
I'm accustomed to using vectors to dynamically add an element. However, vectors does not seem to want to handle an array of objects.
So, my main goal is having an array of objects and then being able to add an element to the end of the array to take another object.
EDIT**
Sorry, its the pushback() that causes me the problems.
class classex
{
private:
int i;
public:
classex() { }
void exmethod()
{
cin >> i;
}
};
void main()
{
vector <classex> vectorarray;
cout << vectorarray.size();
cout << vectorarray.push_back();
}
Now I know push_back must have an argument, but What argument?
Now I know push_back must have an argument, but What argument?
The argument is the thing that you want to append to the vector. What could be simpler or more expected?
BTW, you really, really, really do not want exmethod as an actual method of classex in 99% of cases. That's not how classes work. Gathering the information to create an instance is not part of the class's job. The class just creates the instance from that information.
Arrays are fixed sized containers. So enlarging them is not possible. You work around this and copy one array in a bigger and gain space behind the old end, but that's it.
You can create a array larger than you currently need it and remember which elements are empty. Of course they are never empty (they at least contain 0's), but that's a different story.
Like arrays, there are many containers, some are able to grow, like the stl containers: lists, vectors, deques, sets and so on.
add a Constructor to set i (just to give your example a real world touch) to your example classex, like this:
class classex {
public:
classex(int& v) : i(v) {}
private:
int i;
};
An example for a growing container looks like this:
vector <classex> c; // c for container
// c is empty now. c.size() == 0
c.push_back(classex(1));
c.push_back(classex(2));
c.push_back(classex(3));
// c.size() == 3
EDIT: The question was how to add an element to an array dynamically allocated, but the OP actually mean std::vector. Below the separator is my original answer.
std::vector<int> v;
v.push_back( 5 ); // 5 is added to the back of v.
You could always use C's realloc and free. EDIT: (Assuming your objects are PODs.)
When compared to the requirement of manually allocating, copying, and reallocating using new and delete, it's a wonder Stroustrup didn't add a keyword like renew.
we have a data structure
struct MyData
{
int length ;
char package[MAX_SIZE];
};
where MAX_SIZE is a fixed value . Now we want to change it so as to support
"unlimited" package length greater than MAX_SIZE . one of the proposed solution
is to replace the static array with a pointer and then dynamically allocating
the size as we require For EX
struct MyData
{
int length ;
char* package;
};
and then
package = (char*)malloc(SOME_RUNTIME_SIZE) ;
Now my question is that is this the most efficient way to cater to the requirement OR is there any other method .. maybe using STL data structures like growable arrays etc etc .
we want a solution where most of the code that works for the static char array should work for the new structure too ..
Much, much better/safer:
struct my_struct
{
std::vector<char>package;
};
To resize it:
my_struct s;
s.package.resize(100);
To look at how big it is:
my_struct s;
int size = s.package.size();
You can even put the functions in the struct to make it nicer:
struct my_struct
{
std::vector<char>package;
void resize(int n) {
package.resize(n);
}
int size() const {
return package.size();
}
};
my_struct s;
s.resize(100);
int z = s.size();
And before you know it, you're writing good code...
using STL data structures like growable arrays
The STL provides you with a host of containers. Unfortunately, the choice depends on your requirements. How often do you add to the container? How many times do you delete? Where do you delete from/add to? Do you need random access? What performance gurantees do you need? Once you have a sufficiently clear idea about such things look up vector, deque, list, set etc.
If you can provide some more detail, we can surely help pick a proper one.
I would also wrap a vector:
// wraps a vector. provides convenience conversion constructors
// and assign functions.
struct bytebuf {
explicit bytebuf(size_t size):c(size) { }
template<size_t size>
bytebuf(char const(&v)[size]) { assign(v); }
template<size_t size>
void assign(char const(&v)[size]) {
c.assign(v, v+size);
}
// provide access to wrapped vector
std::vector<char> & buf() {
return c;
}
private:
std::vector<char> c;
};
int main() {
bytebuf b("data");
process(&b.buf()[0], b.buf().size()); // process 5 byte
std::string str(&b.buf()[0]);
std::cout << str; // outputs "data"
bytebuf c(100);
read(&c.buf()[0], c.buf().size()); // read 100 byte
// ...
}
There is no need to add many more functions to it, i think. You can always get the vector using buf() and operate on it directly. Since a vectors' storage is contiguous, you can use it like a C array, but it is still resizable:
c.buf().resize(42)
The template conversion constructor and assign function allows you to initialize or assign from a C array directly. If you like, you can add more constructors that can initialize from a set of two iterators or a pointer and a length. But i would try keeping the amount of added functionality low, so it keeps being a tight, transparent vector wrapping struct.
If this is C:
Don't cast the return value of malloc().
Use size_t to represent the size of the allocated "package", not int.
If you're using the character array as an array of characters, use a std::vector<char> as that's what vectors are for. If you're using the character array as a string, use a std::string which will store its data in pretty much the same way as a std::vector<char>, but will communicate its purpose more clearly.
Yep, I would use an STL vector for this:
struct
{
std::vector<char> package;
// not sure if you have anything else in here ?
};
but your struct length member just becomes package.size ().
You can index characters in the vector as you would in your original char array (package[index]).
use a deque. sure a vector will work and be fine, but a deque will use fragmented memory and be almost as fast.
How are you using your structure?
Is it like an array or like a string?
I would just typedef one of the C++ containers:
typedef std::string MyData; // or std::vector<char> if that is more appropriate
What you have written can work and is probably the best thing to do if you do not need to resize on the fly. If you find that you need to expand your array, you can run
package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;
You can use an STL vector
include <vector>
std::vector<char> myVec(); //optionally myVec(SOME_RUNTIME_SIZE)
that you can then resize using myVec.resize(newSize) or by using functions such as push_back that add to the vector and automatically resize. The good thing about the vector solution is that it takes away many memory management issues -- if the vector is stack-allocated, its destructor will be called when it goes out of scope and the dynamically-allocated array underlying it will be deleted. However, if you pass the vector around, the data will get copied that can be slow, so you may need to pass pointers to vectors instead.