How to initialize a vector in a struct in c++ - c++

I am having a problem with vectors in c++. I am new to c++ so keep this in mind please.
So I have the following struct in the begining of my program:
typedef struct grupo
{
float transX, transY, transZ, rotX, rotY, rotZ, rotAngle, scaleX, scaleY, scaleZ;
char **modelos;
struct grupo** grupos;
int nNomes = 0, nGrupos=0;
std::vector<float> vertices;
};
struct grupo *grupo;
And I just start the main like this:
grupo = (struct grupo*)malloc(sizeof(struct grupo));
grupo->modelos = (char **)malloc(sizeof(1));
grupo->grupos = (struct grupo **)malloc(sizeof(struct grupo));
And in the middle of main I am tryting to use this:
grupo->vertices.push_back(x);
But it keeps crashing the program. I am using visual studio, and using debugging mode. I can see that is when pushing X to the vector that crashes (x has a value). I've tried to change the vector to an array of floats. So the problem i can imagine is with the initialization of the vector... Can you help with what am I missing?
Thank you :)

You're using C++, you don't need the "new" or malloc keyword unless for specific reasons. You don't need the typedef for structs.
I'm not sure what your char** is supposed to be, but you can use std::string for strings.
Maybe what you're trying to do is this:
struct Grupo
{
float transX, transY, transZ, rotX, rotY, rotZ, rotAngle, scaleX, scaleY, scaleZ;
std::string modelos;
int nNomes = 0, nGrupos=0;
std::vector<float> vertices;
};
In main:
Grupo grupo;
grupo.vertices.push_back( ... );
Then I would advise you to read a bit more about what is exactly the C++ language and how it's not C.

Since you're using C++; if you want to create a grupo dynamically, you should use the new operator, with the constructor:
grupo = new grupo();
malloc does not properly initialize C++ objects such as std::vector.
P.S. I am not sure what the grupo->modelos and grupo->grupos are supposed to be, but I'd use proper C++ types for them (perhaps modelos should be std::string, etc). Additionally, I suspect that you've got one * too much for both modelos and grupos.

C++ does not need the typedef in the declaration.
To properly initialize a structure, you should write a ctor to replace the compiler provided ctor (which generally does nothing).
Something like the following (with just a few attributes):
struct grupo
{
float transX, transY;
// ...
int nNomes;
int nGrupos;
std::vector<float> vertices;
// I prefer initialization list form
grupo() : transX(0.0),
transY(1.0),
// ...
nNomes(0),
nGrupos(0)
// vertices default ctor is ok, creates empty vector
{
// use vertices.push_back(...); to fill vertices
}
};
grupo grupo;
Next you will want to write a more useful ctor, one with parameters to use (instead of the literal constants), such that you could build multiple grupo.
grupo grupo1(1.0, 2.0, 3, 4);
grupo grupo2(3.0, 4.0, 5, 6);
// etc.

Related

Can't initialise an array

Okay, I'm pretty new when it comes to C++ (having moved over from VB) and I can't seem to work out how to populate an array without doing:
array[0] = 1
array[1] = 2
etc etc
So as could be expected, I have tried this:
float posVector[3]; //Declared outside of int main() as needs to be global
posVector = {0.0f,0.0f,0.0f}; //Inside int main()
Which is causing this error to be displayed:
extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
Nothing I have been able to locate online so far has been of any help. So any advice you can give me on fixing this will be appreciated!
Once the array is declared it cannot be initialized using the initializer list. You can go with
float posVector[] = {0.0f,0.0f,0.0f};
or even better go with std::vector:
#include <vector>
std::vector<float> posVector = {0.0f,0.0f,0.0f};
It can be done like this:
float f[] = {1.0, 2.0, 3.0, 4.0, 5.0};
Shortest way i think: float posVector[] { 0.0f,0.0f,0.0f };
As far as I understand, the question is not about INITIALIZING the array, but about assigning the array after it was already created. The answer is 'no way'. Arrays can not be assigned after they are initialized. However, arrays of fixed sizes some time might be more adequately presented as structs, and this is exactly the case! Coordinates are much better presented as structs!
Not commenting on the neccessity of global variable (most likely, not needed) here is the way to make it work:
struct Coordinate {
float x;
float y;
float z;
};
Coordinate coord;
void foo() {
coord = {1, 2, 3};
}

How to create multidimensional multitype c++ vector?

I'm looking for a way to create a C++ vector which will hold class object ( which is multi dimensional array - 3D coordinate system location mapper ) and int object which describes it in some way.
I have found many examples of multidimensional single type vectors like
vector <vector<int>> vec (4, vector<int>(4));
I need a dynamic structure which can grow/shrink in the heap as time progress with flexibility of the vector type.
// Your position object, whatever the declaration may be
struct Position { int x, y, z; };
struct Connection {
Position position;
int strength;
};
// This is what you want your node class to be
// based on the comment you gave.
struct Node {
Position position;
std::vector<Connection> connections;
};
// A vector is dynamic and resizable.
// Use std::vector::push_back and std::vector::emplace_back methods
// insert elements at the end, and use the resize method to modify
// the current size and capacity of the vector.
std::vector<std::vector<std::vector<Node>>> matrix;
An alternative would be to define a Connection as an std::pair<Position, int>, but that wouldn't be very good because if you wanted to add more information to the Connection in the future, you'd have to change more code than you should.
If you want to resize the whole multidimensional array, you'll have to iterate over all the vectors one by one with a loop and call the resize method.
You can only get "type flexibility" out of a std::vector is to have it store a polymorphic type. Based on your example, it looks like you may want a std::vector of structs:
struct s
{
int i;
double d;
char c;
bool b;
};
std::vector<s> vec;
// elements can be accessed as such:
auto i = vec[0].i;
auto d = vec[0].d;
auto c = vec[0].c;
auto b = vec[0].b;

Array member declaration and initialization

I want to make vertices an array of Vector. But I don't know how to declare and initialize it. I tried this, but it complains:
class Mesh {
public:
Vector vertices[];
int verticesCount;
Mesh();
virtual ~Mesh();
};
Mesh::Mesh() {
verticesCount = 4;
vertices = new Vector[verticesCount]; // error: expected primary-expression before ']' token
vertices[0] = new Vector(0, 0, 0);
vertices[1] = new Vector(1, 0, 0);
vertices[2] = new Vector(1, 1, 0);
vertices[3] = new Vector(0, 1, 0);
}
Mesh::~Mesh() {
delete vertices;
}
Edit
Trying to correct, applying your tips, I reach this:
Vector* vertices;
//...
vertices = new Vector[verticesCount];
vertices[0] = Vector(0, 0, 0);
vertices[1] = Vector(1, 0, 0);
vertices[2] = Vector(1, 1, 0);
vertices[3] = Vector(0, 1, 0);
//...
delete[] vertices;
And it worked. But is it ok?
You declare vertices as an unspecified array of Vector, then you try to allocate memory for each entry in the array.
First C++ doesn't support empty arrays (if I remember correct), and the data type of the array is not pointers to Vector which means you can not use the new expressions.
If you want to use a dynamic array of vectors, please use std::vector instead:
std::vector<Vector> vertices;
And in the constructor:
vertices.push_back(Vector(0, 0, 0));
// etc.
Array members in C++ must have a compile-time fixed size.
If you want to specify the size of the array at runtime, you must either use a pointer, or preferably a std::vector<Vector>.
Corrections:
Vector* vertices;
[..]
delete[] vertices;
You are declaring an array with an undefined size, compilers might also complain to this by issuing a field has incomplete type error.
Arrays are not pointers. Since an array is included in the memory footprint of the class the size must be known at compile time.
You can either:
use a std::array if size is known a priori
use a std::vector to have a variable sized array
use a pointer Vector *vertices (or Vector **vertices since you are instantiating single vertices)

C++ -- fastest way to set an array of floats to the same value

I naively thought I could use memset for this, but apparently memset is only for chars. Is there a memset-type thing that will work on an array of floats? Or is simple iteration the fastest way to copy a single value to every spot in an array?
I won't speak to what code runs the fastest. You should compare them yourself, in the intended environment.
But, here are two readable, maintainable, correct solutions.
std::fill(std::begin(array), std::end(array), 3.14);
Or, if you have a dynamic array:
std::fill(array, array+size, 3.14);
The standard way is:
std::fill(float_array, float_array + array_size, 0.0f);
I suspect you could beat this standard facility without non-standard methods.
I would recommend std::fill.
std::fill(
floatArray + 0, floatArray + LENGTH
, newValue
);
The compiler knows what you are trying to do here, and decent implementations can provide appropiate optimizations.
You just have to loop through and set all the values to 0 (which is what memset does anyway):
// this is a generic function to set all the elements of an array of any type (that has a public assignment operator and copy constructor) to a specific value
template<typename T>
void setarray(T* array, const T val, unsigned int array_size) {
for (unsigned int i = 0; i < array_size; ++i)
array[i] = val;
}
float* floatArray = new float[x];
setarray(floatArray, 0, x);
If the particular value you want to set all the elements of the array to happens to be 0 and you are using a compile time array, you can use an initialiser list:
float myArray[CONSTANT] = {}; // all values are 0
There is memfill function
http://manpages.ubuntu.com/manpages/natty/man3/memfill.3pub.html
in publib nonstandard library. It can be used in ubuntu.
#include <publib.h>
float a=4.4;
memfill(buf_ptr, buf_size, &a, sizeof(float) );
You can use threads and initialize sub-ranges with separate threads.
If you have a multiple dimensional float array then you could do something like this:
float myMultiDimensionFloats[5][250];
float myfloats[250];
for(int i=0; i<250;i++)
myfloats[i] = 3.14f; // the value you want to store in each float entry
for(int ii=0; ii<5; ii++)
CopyMemory(myMultiDimensionFloats[ii], &myfloats, sizeof(myMultiDimensionFloats[ii]));
Or if you want to use the template from "Seth Carnegie" :
#define LEN(arr) ((int) (sizeof (arr) / sizeof (arr)[0]))
float myMultiDimensionFloats[5][250];
setarray(myMultiDimensionFloats[0], 3.14f, LEN(myMultiDimensionFloats) * LEN(myMultiDimensionFloats[0]));

Flat array from an array of structs?

Hey guys. Thanks for clicking.
This is a problem that I'm encountering while coding OpenGL, but it's a pretty general problem overall - so nothing graphics specific.
I have a struct (not a class, just a simply struct), Particle.
typedef struct
{
float x;
float y;
float z;
}float3;
typedef struct
{
float3 position;
float3 velocity;
//...other stuff
}Particle;
And I am working with a bunch of particles (Particle* particles[]), but I have a function that requires a float* of positions packed in an x, y, z order.
Thus a summary of my problem:
My data:
//I have this in a bunch of encapsulated structs
[... {1.0f, 2.0f, 3.0f,} ... {4.0f, 5.0f, 6.0f} ...]
//I want...
[1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f]
My problem is...I have all the data there already! I don't want to have to malloc/memcpy around again. Is there a way to use the data that is already there? Any C pointer acrobatics? I am also worrying about things like alignment/padding.
(float3 is a struct defined in CUDA, if anyone is curious).
glVertexAttribPointer has a stride parameter that is designed for just this situation.
Typically you will load an array of Particle objects into a VBO, and then, with the VBO bound:
glVertexAttribPointer(shader_arg_position, 3, GL_FLOAT, GL_FALSE, sizeof (Particle), offsetof(Particle, position));
My solution is more C oriented.
The thing with pointers,you can use them to walk freely from one memory address to another with the idea "don't care what data is there". Combine that with the fact that when you allocate structs they are aligned in the order they are declared and you have yourself an easy solution to access your data without too much hassle.
Just make a float* index to point at the beginning of your vector structure where you hold all the points. Using index now you can traverse it how you please, however be careful where you stop with the pointer movement.
To explain a bit:
struct {
float3 position;
float3 velocity;
float3 more_data;
} Particle;
When you allocate this structure the memory will look like this:
3 floats for position || 3 floats for velocity || 3 floats for whatever data
Take a float* at the address position.x and increment it through you particles taking in consideration what data you want to process (position, velocity, etc).
Concerning alignment, it depends what alignment do you want your structure to have.
What about a reinterpret cast and a lot of care here?
Particle* pP[];
// Fill your array of particles
// And now at your own risk (memory accesses and so on... :)
float* pF = reinterpret_cast<float*>(&pP[0]);
float x = pF[0];
float y = pF[1];
float z = pF[2];
pF = reinterpret_cast<float*>(&pP[1]);
// ..
If you have your Particle* array, but you want to work with it as if it were an array of float positions, you could write something like this:
float getNthFloat(size_t n)
{
size_t i = n / 3;
size_t j = n % 3;
float* pF = reinterpret_cast<float*>(&pP[i]);
return pF[j];
}
// This would get 6th element in your virtual float array
// That is, second z position
size_t foo = 5;
float blah = getNthFloat(5);
And going one step further; you could probably rewrite this so it actually looks like accessing an array instead of calling a function.
The ideal solution is to fire whoever designed float3 and replace this structure with simple arrays across the board.
If you can't do that, you can try simply casting the pointer, but you might find your compiler refuses to generate working code since this is a violation of the aliasing rules.
And one more solution:
typedef struct {
float elem[3];
} float3;
#define x elem[0]
#define y elem[1]
#define z elem[2]
Unfortunately the names x, y, and z could be problematic to define as macros like this. That's one reason many classic C structures use prefixed names for struct elements, like st_dev, tv_sec, si_uid, etc...