In C++, How do I store values into a vector that is inside of a vector when the two vectors are of different types? - c++

I am writing a program where I need to use the following data structure:
struct shape
{
std::vector<float> verts; // contains the x & y values for each vertex
char type; // the type of shape being stored.
float shapeCol[3]; // stores the color of the shape being stored.
float shapeSize; // stores the size of the shape if it is a line or point
};
In my main program I need a vector of type shape. How would I store values into the vector inside of the struct shapes using the the vector of struct shapes.
For instance, vector<shape> myshapes;
If I wanted to store a value into the first index of my verts vector, inside of my first index of my myshapes vector how would I do this?
in pseudo code it would look something like this, with i being the index:
myshapes[i].vector[i] = 4; // but I know this is incorrect
Would this be easier to implement using a STL list instead and if so what would that syntax look like?
Thanks for the help I am new to vectors so any advice would be appreciated.

vector supports the use of the [] operator. The syntax and semantics are very similar to using the [] operator with arrays. See: http://en.cppreference.com/w/cpp/container/vector/operator_at.
As with any struct member, you need to access it by name. myshapes[i].verts[j] = 4;.
The general advice given is to use std::vector as your default container of choice. Naturally if you have specific needs (like adding/removing items in the middle of the container) other containers may have better performance characteristics.

If your vector(s) start out empty, you'll have to add elements to them before you can index into them with operator[]. This is usually done with push_back (to add an existing shape object) or emplace_back (to construct a new shape object directly in the vector).
Given vector<shape> myshapes, you could add some shapes like this:
// add 10 shapes
for (size_t n = 0; n < 10; n++) {
shape s; // creates a new, blank shape object
// initialize the shape's data
s.type = ...;
s.shapeSize = ...;
// etc.
// add verts
s.verts.push_back(1.0f);
s.verts.push_back(2.0f);
s.verts.push_back(3.0f);
// etc.
// add the shape to the vector
myshapes.push_back(std::move(s));
}
(Since we're done with s on that last line, we can use std::move. This allows push_back to move the shape's data into the vector instead of copying it. Look up move semantics for more info.)
Once you have stuff in the vector, you can access elements by index like this:
myshapes[index of shape].verts[index of vertex within that shape]
Using [] with an invalid index or when the vector is empty invokes undefined behavior (don't do it or your program will crash/malfunction).

Related

Does an array of vectors form a 2D vector?

Does the following statements form a 2D vector?
Also mention the dimensions of the vector if it does. Is there another way of declaring a global 2D vector?
Statements:
vector<int> *adj;
adj = new vector<int>[number_of_nodes];
The above statements have been used for declaration of a global adjacency matrix for a graph.
It seems the question isn't clear to much of you. I want to declare a global adjacency list using vectors such that I can use direct addition of edges in graph like v[a].push_back(b). For that, I have to specify first dimension of vector while declaring which I don't have until the main is executed.
No, but it gives similar behaviour. So what you have created is a pointer to an array of vectors. So you will end up with this:
adj[0] = []
adj[1] = []
...
adj[number_nodes] = []
and doing a push_back is a legitimate way to add to the vectors:
adj[0].push_back(some_num) --> adj[0] = [some_num]
But this is a terrible way to approach this! Why?
You are using raw memory that you will have to manage and make sure you delete.
You cant use any of the awesome std::vector functionality on the first dimension of the matrix.
There is no good way to figure out the size of the vector unless you know about the variable number_of_nodes.
... A long list, but you get it.
You can already see that a std::vector can be used as a 1D matrix. So use 2 vectors:
std::vector<std::vector<int>> Matrix2D;
If you need an initial size in some dimension then you can do this:
std::vector<std::vector<int>> Matrix2D(number_of_nodes, std::vector<int>());
Or this:
Matrix2D.resize(number_of_nodes);
Or if that size is fixed at compile time then you could even do this:
const int number_of_nodes = 10;
std::array<std::vector<int>, number_of_nodes> Matrix2D;
Or go extra big and get a library for Matrix use like Eigen.

C++ : Null pointers and structs

If I want to make a struct for representing an item to render on the screen, and contains:
A list of natives "renderables" (meshes, triangles, etc)
A pointer to others sub-structures
Does this:
struct RenderGroup {
std::vector<RenderGroup*> Children;
std::vector<Renderable> Renderables;
}
What is the best way to do this? And if I have no sub-structures, can I just put a null pointer in the vector ?
Edit : Bad tags
A std::vector is not fixed size, so if there are no elements in it, size will return 0 and empty will return true.
std::vector<int> v;
auto sz = v.size(); // sz has value 0
auto e = v.empty(); // true
v.push_back(42);
sz = v.size(); // 1
e = v.emi empty(); // false
You can also remove elements (the vector moves all the followingv elements down to fill the gap)
std::vector<int> v { 1, 2, 3 };
auto it = v.find(2);
if (it != v.end())
v.erase(it); // v now contains 1, 3
So, in theory, no you don't need to put nullptrs in your vector. This assumes you've designed your application in a way that doesn't require a certain population size in your vector; if so, vector might not be the right container. Consider std::array.
There is a problem with your renderables vector, though: the vector stores instances of Renderable. The elements I'm the vector are exactly the size of a Renderable. So if you try and store a derived class, e.g Mesh, you will lose the derived classes extra fields.
This is called slicing. https://en.m.wikipedia.org/wiki/Object_slicing
You'll need to store pointers or references to the instances of the objects. Which depends on lifetime and ownership of the instances.
If your vector owns the remediables, you could use std::vector<std::unique_pre<Remediable>>.
If you are being given the instances from your caller, perhaps std::shared_ptr.
There's no need to put arbitrary "nothing" records in a std::vector, this isn't like a variable-length C-style array where you must terminate with some kind of delimiter. Just leave it empty.
In general practice you want to avoid putting NULL into lists like this where something might iterate over the contents and re-reference that pointer, causing a crash.
If RenderGroup is a base class and your Children vector is storing arbitrary children classes of RenderGroup then this approach is "fine" (though smart pointers would probably be preferred).
However, as tadman mentioned, if you're using pointers to represent the absense of a RenderGroup, you'll probably want to instead just remove the items in the vector when they are no longer needed.
See if this structure can help:
struct RenderGroup {
std::map<Renderable, std::vector<RenderGroup*>> Renderables;
}
List of child (RenderGroup) objects are mapped to Renderable object.

How to store object pointers in an array

I'm fairly new to c++ and this problem's got me bad.
In my project I'm using SFML libraries to create asteroids. I declared a class named _asteroids and want to create a bunch of asteroid objects inside the class. Someone suggested I stored the objects inside an array. Later I learned that it wasn't possible to store objects inside an array, but you could store pointers to objects.
In summary I want to:
-Create objects inside the _asteroids class
-Store the pointers to those objects inside an array
-Be able to call those objects by their pointers from the array and change their values
How do I go about doing that? Here is some of my code to do with this:
class _asteroids{
float angle; //Angle
sf::Vector2f a_pos; //Position
sf::Vector2f a_vel; //Velocity
void makeAsteroids(int); //This generates the asteroid's appearance
bool Remove(); //If this is false the object is removed
public:
void Update(); //This updates the position
};
In C++ you should - if at all possible/reasonable - avoid (raw) pointers and C-style arrays. C++ provides standard containers. Like C-style arrays they can hold all kind of element types but they have some benefits that a C-style array doesn't. For instance most containers can grow/shrink when you need it - in other words, their size can adjust itself as you add or remove elements. On top of that, they have a number of member function that will allow you to operate on the contained elements in an easy way.
The vector container is very popular. In many aspects it is just like an array once the elements have been added, i.e. you access elements using var[i]. You can add elements to the end of the vector using push_back.
Example:
std::vector<_asteroids> allAsteroids;
allAsteroids.push_back(_asteroids()); // Add _asteroids object to end of vector
allAsteroids.push_back(_asteroids()); // Add _asteroids object to end of vector
allAsteroids.push_back(_asteroids()); // Add _asteroids object to end of vector
cout << allAsteroids.size() << endl; // Will print 3
for (auto& a : allAsteroids) // Iterate over all asteroids in the vector
{
a.Update(); // Call Update for current element
}
// The same as above in a different way
for (int i = 0; i < allAsteroids.size(); i++)
{
allAsteroids[i].Update(); // Call Update for i'th element
}
This was just a few examples of what you can do with vector. There are many more.
Check http://www.cplusplus.com/reference/vector/vector/ for more information - all member function of vector is shown to the left on that site.
Sure you can save Asteroid within an std::vector
class Asteroid {};
std::vector<Asteroid> asteroids;
Asteroid as1;
asteroids.push_back(as1);

Arrays and overwriting in C++ - can I reuse the same object?

I'm making an array of vectors to save as normals. Because we haven't learned how to do vectors in class yet, I've made a struct which serves just as well:
struct vector3
{
double xcoord;
double ycoord;
double zcoord;
};
Then, at the beginning of my function, I have this:
vector3 vector;
vector3* normalField = new vector3[x];
While the function loops through, in each loop, it applies new values to "vector" - at the end of the function, it sets a part of the array to be vector.
normalField[x] = vector;
The idea is to save memory by not creating a whole bunch of new vectors, and because I have no clue when and where I would be able to use the delete function on that group of vectors. Will this work? Or not? What's the best way of doing this?
The code is very wordy as a whole - I'm writing an algorithm to create a field of normals for procedurally generated terrain. I don't use the built-in vector class because we're not supposed to for some stupid reason. I blame the professor.
The assignment normalField[x] = vector is going to deep copy the data in vector; you will be creating as many vectors as there are elements in normalField[].
Remember too that in C++ the only difference between a struct and a class is that in a struct data members and functions are public by default, but in a class they are private by default.
What you want can be implemented either via array, and creating a new, bigger array when your need for vectors is increased (essentially replicating the behaviour of std::vector), or by using a linked list, which could look like this:
struct vector3List {
vector3 v;
vector3List * next;
};
More refined solutions exist, of course, but the choice depends on what you need to do on the vectors.
In case you are not sure how a list is used, here is an example:
vector3List * listBegin = new vector3List();
// Setup your vector
listBegin->v.coordX = 6;
// Set the end of the list
listBegin->next = 0;
// You need one more vector
listBegin->next = new vector3List();
// Use some kind of helper pointer to keep track of what vector you are examining
// if you need it
vector3List * iterator = listBegin->next;
// Setup this new second vector
iterator->v.coordX = 5;
// Remember to set the end of the list!
iterator->next = 0;
// Iterate throgh the list
iterator = listBegin;
while ( iterator != 0 ) {
// Do stuff
iterator = iterator->next;
}
This is, of course, a naive implementation, but you get the idea.

C++ Regarding assigning value to Vector<Point> myVariable

C++ Regarding assigning value to Vector myVariable
Hi guys.
I have this struct
struct Point
{
int x,y;
}
and in my main.cpp i got something like this
int main()
{
vector<Point> myPoints;
myPoints[0].x = 1;
myPoints[0].y = 1;
myPoints[1].x = 2;
myPoints[1].x = 2;
return 0;
}
and i get segmentation core dump, what is wrong with setting value to the element of the vector.
Thanks for guiding!
vector<Point> myPoints;
creates an empty vector of Point objects. Since it's empty, you can't access myPoint[0], myPoint[1] etc. Attempting to do this won't auto-create elements; instead, it will invoke undefined behaviour – quite typically a segmentation fault.
Use push_back to append elements to the vector:
myPoints.push_back(Point(1,1));
or, alternatively, resize the vector so it contains default-constructed elements:
myPoints.resize(2);
You can also use an argument to the constructor of std::vector to resize it right at initialization time:
vector<Point> myPoints(2); // auto-resizes the vector to length 2
Note about push_back. In C++11, you may use emplace_back() instead of push_back() as well: myPoints.emplace_back(1,1); appends a new element to the vector by calling the Point constructor in-place, using 1,1 as the arguments to the constructor. This is the most efficient way of appending newly created elements to the vector.
You didn't initialize any objects. You need to make the objects and then put them into the vector, otherwise you are acting on something that does not exist, which is causing the segfault.
Example:
Point myPoint;
myPoints.push_back(myPoint);
myPoints[0].x = 1;
The problem is that you are trying to access elements which have not been created yet.
After this line:
vector myPoints;
you have a vector myPoints which has exactly 0 elements. Thus, myPoints[0] is meaningless.
You need to do one of the following:
Create a vector with a pre-determined size: vector<Point> myPoints(2); (note: you can expand or shrink it later), then execute myPoints[0].x=1 etc.
Use the vector's push_back method to add new elements to the vector, i.e. myPoints.push_back(Point(0, 0));
After you declare the new vector object, use the resize method to allocate space for two new elements.