I have a c++ class that is contained as a vector of objects in another class.
class Small
{
public:
int a;
int b;
int c;
};
class Big
{
public:
vector< Small > getSmallVec() const { return m_smallVec;}
private:
vector< Small > m_smallVec;
};
I'd like to be able to access the members of the Small class as a vector themselves. In other words, I'd like to have a function in Big like
vector<int> getSmallVec_a()
which would return a vector that contains each value of int Small::a in m_smallVec. The only way I can think of doing it would be to iterate over m_smallVec and copy to a vector of int. Is there a way to do this without copying?
If this is how you expect to access data and performance is important, have you considered using parallel vectors? Instead of
std::vector<Small>
In "Big" you actually maintain 3 vectors
std::vector<int> aVec;
std::vector<int> bVec;
std::vector<int> cVec;
All elements at 0 correspond to the 0'th "Small", and you can easily seperate out all the as from the bs.
This comes a lot of annoying bookkeeping that you'd be have to be sure to get right and encapsulate well. Its not a more elegant solution, I usually dislike this kind of thing and would probably question in a code review, but it would probably give you the best performance for the operations you've described.
there is no way to do that without seperating small components in diffrent vectors since a vector is just working as an array that means when you are creating a vector of smalls there will be 2 blocks space between small::a variables whereas what you what to return is just an array of ints. and by the way it's much more efficient if you delcere you function as vector <int> & getSmall() since if you don't return a refrence it'll cause a copying m_smallVec and returning it as the result, it also makes it impossible to change any value in m_smallVec.
Related
I have an array of a struct, lets say
struct cell{
int pos;
int id;
};
std::vector<cell> myArray;
I want an array of the id element. I can't just iterate over my array as it would take too long.
I have to provide std::vector<int> to a function.
My thought process was: Since arrays are usually just a pointer to the first element and then an offset I thought of creating an array where i can provide the offset, such as it would point to the id element of the next cell in std::vector<cell> myArray.
One solution I can think of is having an array of pointers to that element, for example:
The final solution might be something like:
struct cell{
int pos;
int id;
};
std::vector<cell> myArray;
std::vector<int*> pointersToIds;
// Creating an array of int from an array of int*
std::vector<int> idsArray = std::something(pointersToIds);
myFunc(idsArray);
Since the std library has tons of stuff I supposed there would be a way to do this.
Is there a way to convert the array of pointers to an actual array of elements in a very optimized way? The pointers approach was the only i could think but it's doesn't necessarily have to be it.
Thank you all in advance :)
I tried iterating over the the array of pointers and creating an array of elements, but it would take too much time.
TLDR Get array of an element from array of struct
I suppose this might be an instance of The XY Problem, since it's not clear what you are actually trying to solve, do you:
Want to find a fast way to pass the list of struct to a function
Want a way to extract all the members from a list of struct into a list of members
First off, shoo away from your mind the idea of manually creating an array of addresses and then fiddling around with the offsets yourself, this is certainly doable, but probably hard to do yourself in a safe and portable way due to Struct Alignment, something that differs from machine to machine.
besides accessing cell.id is already doing that in a portable way by itself!
Problem 1.
If you want to pass a vector (or any object really) to a function in a fast way, you can use a reference, it would look something like this:
void foo(std::vector<cell>& in_vec);
notice the & operator, declaring that in_vec must be passed as a reference, what this does internally is pass in_vec by address, avoiding copying values one by one, C++ does all this by himself and you can treat in_vec normally in the function without a care in the world, and it's blazing fast.
Problem 2.
if your point is that you want to extract all the IDs before passing them to a function, first off, I still suggest you pass the cell, that way it is clear that foo is supposed to operate on cell IDs and not random integers, once again, paying the cost of unpacking the structs outside (which warrants an iteration) or inside (where you might not even need to access all cells depending on foo's nature) is equal if not worse.
If you must carry through, it's as easy as a for loop:
std::vector<int> ids;
for(auto const& cell : myArray)
{
ids.push_back(cell.id);
}
Or, if you want a elegant and modern solution, using lambdas and algorithm:
#include <algorithm>
std::vector<int> ids;
std::transform(myArray.begin(), myArray.end(),
std::back_inserter(ids), [](cell const& c) {
return c.id;
});
Or something to this effect.
I've created a class that I would like to use in a std::vector of considerable size. However, within that class are members that won't change for each element in the vector (cartesian in the example below). Is there a way to create my class so when I make a vector of it, all the elements in the vector reference to the same variable? Or, more importantly, a way to not use memory for a member that will be the same throughout the entire vector? I don't want to use static because it will remain so for all instances of the class, and this value may change for each vector.
for example
class foo
{
public:
int x,y,z;
bool cartesian;
foo(int _x =0, int _y=0, int _z=0, int _cart = true)
:x(_x), y(_y), z(_z), cartesian(_cart)
{
/* code */
}
};
int main(){
std::vector<foo> vec1;
vec1.emplace_back(0,0,1);
vec1.emplace_back(0,0,2);
vec1[0].cartesian = false;
cout<< vec1[1].cartesian << endl;
return 0;
}
I'd like to set cartesian once and have it change for the entire vector (so in this case the 2nd element cartesian member would also become false. Even better I'd like to not use the memory to create it for each element in the vector.
No. Just create an associated variable, and pack it together with the vector in a struct.
struct SomeFoos
{
std::vector<foo> theFoos;
bool cartesian;
};
To answer your question: not really. In c++ instances of a single class are identical in their structure. Even if you have a shared reference to a value you want to share, you will gain no benefit in terms of memory usage, unless the value is an object larger than sizeof(void*).
But since you say "I'd like to set cartesian once and have it change for the entire vector" which I read: "set cartesian attribute for the vector":
I suggest that you create a container class that has vector as superclass; your class will inherit vector's behaviour, and you can add the shared values in instances of that container class.
I have a vector of pairs of let's say ints. Now there is a library that expects a const vector<int>& reference as an input to one of its functions. Is there a way of passing the appropriate vector to the function without copying data? Because all solutions for extracting vectors here on SO always deal with the scenario that I need to extract and copy parts of the vector, but I don't want to copy as I only pass the subvector as read-only const.
Note: I cannot change the function I am calling (that expects const vector<int>&) as it is not part of my code.
EDIT: As I was not clear what I actually want to extract, I will try to clarify. I have a vector<pair<A,B>> and want to pass vector<A>.
No. std::vector<std::pair<int>> and std::vector<int> are completely unrelated types. You can't pass one where the function requires the other. You will have to copy the data.
This is slightly sad because the vector of pairs must have an array of adjacent pairs, and in reality, the pairs will just contain adjacent ints, so the memory layout you need is there. The truth is though, that there is no way to get at it.
Edit
I see from comments that it's more like std::pair<int, char*> in which case you are really stuck.
I think "write your own container" which can expose a std::vector<int> const& for use in this other function, or just copy, is your best bet.
What about something in the taste of:
class container : private std::tuple<std::vector<Device>, std::vector<CommandQueue>>
{
public:
std::tuple<Device, CommandQueue> tuple(size_t index)
{
return std::make_tuple(get<0>.at(index), get<1>.at(index))
}
const std::vector<Device>& devices() const { return get<0>; }
const std::vector<CommandQueue>& commandQueue() const { return get<1>; }
};
You can try to use vector<int> to store your data, and write an adapter class which will expose it using interface compatible with vector<pair<int,int>> for your code.
Edit: The below question was answered by this. I have a new updated question, is it any more efficient to use: (my friend said it is inefficient to put a vector of a vector because it uses sequential memory and to realloc when you push_back means it takes more time to find the location where a chunk of memory for the entire large vector can be placed)
(where Picture is a vector of lines, Line is a vector of points)
std::vector<Point> *LineVec;
std::vector<Line> PictureVec;
versus
std::vector<Point> LineVec;
std::vector<Line> PictureVec;
struct Point{
int x;
int y;
}
I'm trying to get a vector of a vector and my friend told me that it's inefficient to put a vector of a vector because it uses sequential memory and vector of a vector will require huge amounts of space. So what he suggested was a using a vector of a pointer vector. Therefore the inner vector looks like this. Clearly I'm very new to C++ and would appreciate any insight.
struct Shape{
int c;
int d;
}
std::vector<Shape> *intvec;
When I want to push back into this, how would I do so? Something like this?
Shape s;
s.c=1;
s.d=1;
intvec->push_back(s);
Also, I wrote an iterator to go through, however it does not seem to work, hence why I believe the above code does not work. Finally my last concern is, while the above code works, it gives really weird values for my output. Large numbers that are 7 digits long and definitely not the values I put in for s.c and s.d
for(std::vector<Shape>::iterator it=Shapes->begin();it<Shapes->end();it++){
Shape s = (*it);
std::cout << s.c << s.d << std::endl;
}
Using a vector of pointers to vectors is not more efficient than a vector of vectors. It's less efficient, because it introduces an extra level of indirection. It also does not cause all elements of the resulting 2-d array to be allocated contiguously.
The reason is that a vector is practically a pointer to an array, in the sense that a vector<T> is implemented roughly as
template <typename T>
class vector
{
T *p; // pointer to array of elements
size_t nelems, capacity;
public:
// interface
};
so that a vector of vectors behaves, performance-wise, like a dynamic array of pointers to arrays.
[Note: I can't quote the C++ standard chapter and verse, but I'm pretty sure it constrains std::vector's operations and complexity in such a way that the above is the only practical way of implementing it.]
As to your updated question about whether or not it is more efficient to use a pointer to a vector over a vector itself. In some cases it is more efficient to use a pointer to a vector rather then the actual vector itself. A specific example would be using a vector as a parameter for a function.
EX:
void somefunction(std::vector<int> hello)
In this case the copy constructor for std::vector is invoked any time this function is called (which copies the vector completely, INCLUDING the elements contained in the vector). Passing by reference gets rid of this extra copy.
As for whether push_back itself is more efficient when using a pointer to a vector. No its not more efficient to use a pointer (they should be roughly equivalent time wise).
I have this data structure Seq which inherits the class vector but has some extra functionalities.
Using this data structure Seq I have this predefined data structure:
typedef Seq< vector<int> > MxInt2d;
I want now to have a vector of several components of type MxInt2d;
I was thinking about something like:
MxInt2d* loops;
it is just that I think I have to initialize this vector and I do not have a constructor for it. should I write a constructor in order to initialize it ?
So if on one hand I would have the declaration of the following data structure:
MxInt2d myEdges_;
which is then initialized.
And on the other hand the declaration of my variable loops:
vector<MxInt2d> loops;
If I want to copy in loops[0] the first 5 elements of myEdges_, I would use the syntax:
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);
The program gets compiled but when I run it I obtain a bus error message..
The same stuff happens if I use the initialization for a second loop:
for (int i=0;i<5;i++){
loops[1].push_back(myEdges_[i]);
}
(sorry for my bad judgement, I am really new with vector)
madalina
Before getting into your problem-- an observation:
Are you inheriting the vector ? Deriving vector is not a good idea. All the the standard STL containers, lacks a virtual destructor, and publicly inheriting from classes without virtual destructors is a major C++ no-no.
Don't use pointers, unless you have to. Use vector again:
vector<MxInt2d> loops;
Right now, the loops container is empty (i.e. there are no matrices inside). If you want it to contain 2 MxInt2d object, you'll either have to insert them or initialize loops differently:
// loops will contain two empty MxInt2d objects
vector<MxInt2d> loops(2);
// after the following command,
// loops will contain 3 MxInt3d objects
loops.push_back(MxInt2d());
Only after you've populated loops you can start populating its elements.
It's not a good idea to inherit from STL containers because they don't have virtual destructors, which can lead to underfined behaviour, if you try to delete a derived pointer through a base pointer (hope I got that right).
As it is, your data structure looks complex. By creating a pointer of it, you are making it even more complicated. It's better if you can create an array/vector of MxInt2d instead of making it a pointer.
No, not necessarily. std::vector will initialize all elements to 0, so if this is what you need, you won't have to write a custom constructor.
Arrays are evil in C++. You can use vector for almost anything that you can use array for. One common problem; that of initialization can be solved. Refer to this discussion how-to-initialize std::vector like 'C' array.
So, you can use 'vector loops;' without problems.
HTH,
You have a couple of problems here.
One, you should not derive from vector. If you need code that does custom stuff with a vector, you should write a class with your custom stuff that has-a vector, not is-a vector. For example:
class Seq
{
public:
// assorted constructors
// construct vec_ with zero elements
Seq() {};
// construct vec_ with one element
Seq(int singleItemToAdd)
: vec_(1, singleItemToAdd) {};
// construct vec_ with 'multipleItemsToAdd' elements
Seq(const int* multipleItemsToAdd, size_t numItemsToAdd)
: vec_(multipleItemsToAdd,multipleItemsToAdd+numItemsToAdd) {};
// assorted custom operations (instead of deriving from vector)
void customSeqOperation() const
{
/// your custom stuff here
: :
}
private:
vector<int> vec_;
};
Next problem, you are saying this code compiles but crashes at runtime:
vector<MxInt2d> loops;
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);
If this is your essentially compete code, the reason why it crashes is because there is no element at loops[0] -- you haven't added it yet. You need to add an element to loops (which is a vector) before you can access the first one:
vector<MxInt2d> loops;
MxInt2d firstElement = getTheElement();
loops.push_back(firstElement);
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);