I have two arrays
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float normals[] = {
0.0, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f
};
I first want to add the vertices array to a std::vector<float> and after that insert the normals array to the vector.
What I can think of is running a loop based on the sizeof(Array) and push back individual element to the vector.
Would that guarantee that the values inserted are in the correct sequence when I access them back?
You can std::vector::insert the elements in the end of the vector.
#include <iterator> // std::cbegin, std::cend, std::size
#include <vector>
std::vector<float> vec;
// reserve the memory for unwated reallocations.
vec.reserve(std::size(vertices) + std::size(normals));
vec.insert(vec.end(), std::cbegin(vertices), std::cend(vertices));
vec.insert(vec.end(), std::cbegin(normals), std::cend(normals));
[...] running a loop based on the sizeof(Array) and push back
individual element to the vector. Would that guarantee that the values
inserted are in the correct sequence when I access them back?
Yes, indeed. Remember you can use std::size to find the size of the array, if you have access to c++17 or later compiler.
You may want to append those two arrays to an existing std::vector or create a new one out of them. In both cases, you very likely want to reserve all the memory needed for the insertions in one go to avoid additional unnecessary reallocations.
For the former case, you can use the following function template:
template<size_t... Ns>
void append_to_vector(std::vector<float>& vec, float (&...arrs)[Ns]) {
constexpr auto num_elements_to_append = sizeof...(Ns);
vec.reserve(vec.size() + num_elements_to_append);
(vec.insert(vec.end(), std::cbegin(arrs), std::cend(arrs)),...);
}
Appending vertices and normals to an existing std::vector<float> becomes:
std::vector<float> vec; // your existing vector
// ...
append_to_vector(vec, vertices, normals);
For the latter case – i.e., you want to create a new vector out of those two arrays – you can use the following function template, create_vector, that in turn calls append_to_vector:
template<size_t... Ns>
std::vector<float> create_vector(float (&...arrs)[Ns]) {
std::vector<float> vec;
append_to_vector(vec, arrs...);
return vec;
}
Creating a new vector from the arrays vertices and normals comes down to a single line:
auto vec = create_vector(vertices, normals);
You are not limited to two arrays. You can actually provide an arbitrary number of arrays to these function templates thanks to their variadic nature, e.g.:
auto vec = create_vector(vertices, vertices, normals, vertices, normals);
The line above works as you may expect, i.e., it creates a new vector resulting from the concatenation of the elements in vertices, vertices (again), normals, vertices and normals.
In any case, for each call to append_to_vector(), only one reallocation will be performed at most because the call to std::vector::reserve() ensures that the memory needed to insert the new elements is available before the insertions.
To insert elements into a std::vector of floats, you can use std::copy:
std::vector<float> my_vector;
my_vector.reserve(std::size(vertices) + std::size(normals)); // optional
std::copy(std::begin(vertices), std::end(vertices), std::back_inserter(my_vector));
std::copy(std::begin(normals), std::end(normals), std::back_inserter(my_vector));
The order of elements in my_vector will be the same as in vertices and normals.
Do we need to reserve the memory before inserting the Arrays ?
Technically, no. But reserving memory might help to avoid unnecessary reallocations.
Edit.
The Notes section for std::vector::reserve at cppreference reads:
When inserting a range, the range version of insert() is generally preferable as it preserves the correct capacity growth behavior, unlike reserve() followed by a series of push_back()s.
The recipe in my answer works, but that in JeJo's one should be preferred.
Related
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 7 years ago.
I'm working on DirectX and I have a function that gives a predefined array of custom vertices, it is
CUSTOMVERTEX* createSampleTriangle()
{
CUSTOMVERTEX verts[] =
{
{320.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_ARGB (0, 255, 0, 0), },
{250.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_ARGB (0, 0, 255, 0), },
{50.0f, 400.0f, 0.5f, 1.0f, D3DCOLOR_ARGB (0, 0, 0, 255), }
};
return verts;
}
Now, I pick up the result like this:
CUSTOMVERTEX *v = createSampleTriangle();
but as I do line by line debugging I see only one vertex under v, even though verts shows 3 vertices under it. The program doesn't crash, but then again DirectX just doesn't render when something goes wrong, it just skips the function.
any idea why this happens? Does the function not return a pointer with allocated memory that is after that handled by v?
You're returning a pointer to a local automatic object that has ceased existing when you return.
That's Undefined Behavior, of the kind known as a dangling pointer.
Make that object static, or allocate it dynamically, or something. I would go for using a std::vector.
The problem as I see here, verts is having automatic storage duration and local to the function createSampleTriangle(). Returning the address of it and therefore using it later will invoke undefined behaviour.
To elaborate, verts only exist in the stack allocated for createSampleTriangle(). Once this function has finished execution, then there is no existence of verts. So, using the returned value (pointer) from the createSampleTriangle() in the caller function will be wrong and result in UB.
I'm using Eigen3 2-dimensional vector as 2D point for opengl drawing, storing them in a list:
typedef Eigen::Vector2d Vec2D;
std::list<Vec2D> points;
Now, I need an array of GLfloat to pass the entire data structure of raw float coordinate value to the graphic card:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
_vertex = new GLfloat[points.size()*2];
_colors = new GLfloat[points.size()*4];
std::list<Vec2D>::const_iterator it;
int i=0, j=0;
for(it=points.begin(); it!=points.end(); ++it) {
_vertex[i] = it->x()+2;
_vertex[i+1] = it->y()+2;
i+=2;
_colors[j] = getRed(j/4.0f, it);
_colors[j+1] = getGreen(j/4.0f, it);
_colors[j+2] = getBlue(j/4.0f, it);
_colors[j+3] = getAlpha(j/4.0f, it);
j+=4;
}
glColorPointer(4, GL_FLOAT, 0, _colors);
glVertexPointer(2, GL_FLOAT, 0, _vertex);
glDrawArrays(GL_LINE_STRIP, 0, points.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
delete _vertex;
delete _colors;
Is there a more efficent way for creating the arrays to pass to the graphic cards? like pass points.begin() and find out what is the offset and avoid to loop through all the points?
I mean.. in the memory the x and y coordinates of the Eigen::Vector2d has to be stored in some consecutive space.. so.. I think I can pass it directly to the graphic card.. but I can't unserstand how.
std::list does not hold it's data in contiguous memory, you need std::vector for that(or std::array if you know the size at compile time, but you probably don't). Vector has a method data() which returns a pointer to underlying data. However if you store internally Eigen::vec2d you can't pass it to openGl, since it's a dynamic structure and your data will be all over your memory. You need structure that keeps data in place(and btw is more readable than vec2d, which is kinda odd in this context). For example:
struct VertexData
{
GLfloat x;
GLfloat y;
GLfloat red;
GLfloat green;
GLfloat blue;
GLfloat alpha;
}
And then use glVertexPointer to pass it to openGL using sizeof(VertexData) as stride
To delete new'ed arrays you need to use
delete [] _vertex;
normal delete will only free the first element. Or even better, you could use smart pointers, std::unique_ptr would be best in this case
std::unique_ptr<GLfloat[]> _vertex(new GLfloat[points.size() * sizeof(GLfloat)]);
It will automatically free the memory when it goes out of scope(at the end of the block)
points is a std::list so it doesn't contain an contiguous array of data.
If you use std::vector instead however, then in C++11 you can access the array used internally with points.data(). This means you don't need _vertex anymore.
Know that, as an alternative, you can even go further and have a class (named for instance Vertex) which contains both the vertex position and its color and then use the data() method on your std::vector<Vertex> in combination with glInterleavedArrays (with stride=sizeof(Vertex)).
I have a struct array like this:
struct VERTEX_FMT
{
float x, y, z, u, v;
const static DWORD FVF = (D3DFVF_XYZ | D3DFVF_TEX1);
};
VERTEX_FMT vertices[] = {
{-1.0f, -1.0f, 0.0f, 0.0f, 0.0f},
{-1.0f, 1.0f, 0.0f, 0.0f, 1.0f},
{ 1.0f, -1.0f, 0.0f, 1.0f, 0.0f},
{ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f},
};
Is there an easy to way assign the struct array a new value in C++.
Only if you wrap the array in another struct. Arrays are pretty broken in C, and C++ decided that std::vector was sufficient, and that any attempt to fix C style arrays either wouldn't go far enough to make a difference, or would break compatibility to a point where you couldn't talk of C style arrays any more.
For POD arrays like yours, memcpy is by far the simplest solution. For more complicated cases, and even most cases of arrays of structs like yours, you should probably consider using std::vector instead. Or a mixture: use the C style arrays for static, initialized arrays such as the one you show, so that the compiler will count the number of elements for you, but use std::vector for anything which isn't completely initialized in the definition, or which is the target of an assignment. It's easy to construct the std::vector from a C style array using the two iterator constructor of std::vector, so there's no real inconvenience in having both types.
if you mean insert a new value, then no - the array is fixed size - you cannot change it easily. You'll have to create a completely new array - what you should really do is look at std::vector
std::vector<VERTEX_FMT> new_array(vertices, vertices + sizeof(vertices)/sizeof(VERTEX_FMT));
// add the new entry in
new_array.push_back(...);
EDIT: based on the comment, it appears that what you want to do is something like:
vertices[2] = {....}; // new values.
Quickest way to do this in the current standard is to use a std::memcpy or std::copy, something like:
VERTEX_FMT nv = { ... };
// copy this in
std::memcpy(&vertices[2], &nv, sizeof(nv));
// the line below also works if you want to use purely standard algorithms.
//std::copy(&nv, (&nv) + 1, &vertices[2]);
You can use std::generate, or some other stl algorithm function.
As already said, there are no other ways to do it in the current version c++ (it will be possible in c++0x)
In current standard, you cannot do,
int a[3] = {1,2,3};
a[] = {4,5,6};
But you can definitely get its effect using pointer to an array type,
int a[3] = {1,2,3}, (*p)[3]; // <-- this syntax forces p to point only int[3]
p = &a;
int b[3] = {4,5,6,};
p = &b;
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...
I am having issues counting the array elements after passing it into an arguement
void GXDX::LoadMesh(GXVector vertices[], UINT indices[] = NULL)
{
D3D10_BUFFER_DESC bufferDesc;
UINT numVerts = sizeof(vertices)/sizeof(GXVector);
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(GXVector) * numVerts;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bufferDesc.MiscFlags = 0;
bufferDesc.CPUAccessFlags = 0;
code..............
}
In the following line above
UINT numVerts = sizeof(vertices)/sizeof(GXVector);
I am trying to count the number of elements in the array varible vertices. But I am not getting an accurate count, if not one at all.
When I did a step through, I notice that I am not able to see all the values in the array, only the first value of the array.
So I am not sure if I am passing the array correctly as an arguement. In another application, I did the same thing and i was able to see all the values in the step through. I pass the array like this.
GXVector vertices[] = { {D3DXVECTOR3(0.5f, 0.5f, 0.5f)},
{D3DXVECTOR3(0.5f, -0.5f, 0.5f)},
{D3DXVECTOR3(-0.5f, -0.5f, 0.5f)},
{D3DXVECTOR3(-0.5f, -0.5f, 0.5f)},
{D3DXVECTOR3(-0.5f, 0.5f, 0.5f)},
{D3DXVECTOR3(0.5f, 0.5f, 0.5f)},
};
UINT indices[] = {0,1,2,3,4};
GXRenderManager::Device()->LoadMesh(vertices, indices);
So in a nutshell, Am I passing the array right as an arguement, what am I doing wrong where I can not get the correct element count of the array.
Yes, you are passing the array correctly; however, in C (and C++), arrays don't contain their size. So you need to pass the size of the array as a separate parameter. Arrays effectively decay into pointers when passed as a parameter into a function, so sizeof(vertices) will give you the size of the pointer type, not the size of the array. You can walk through the array though, either with pointer arithmetic or indexing - but you need to know its exact size, otherwise you can get out of bounds.
This is one main reason why in C++ std::vector is recommended to use instead of raw arrays.
You are passing the array correctly. Array parameters simply do not remember their lengths. Instead, they're passed as though they were mere pointers, so your sizeof expression is getting the size of a pointer, not the size of the entire array that the pointer points at.
If the function needs to know the lengths of the arrays, then you need to pass the lengths as additional parameters.
C arrays (which is what you're passing) don't pass the size (length) along unless you explicitly specify the array length in the function declaration. The typical way to solve this in C is to pass the array length into the function as well as the array.
In C++ much better is to use a std::vector and pass it around. It already knows its own size and the problem vanishes compeltely.
The sizeof(vertices) operation that you are doing is not a runtime operation, it is actually resolved by the compiler. So, as long as the declaration of the array is in scope, you will get a correct result.
That is not so in a function, because you could be passing arrays from several other points in the code, hence the incorrect result. (And hence the confusion for the debugger as well).
Arrays decay into pointers when you pass them like that. What kind of sense did you think that UINT indices[] = NULL made?
You can pass the length around with the array, like you would have in C, or you could use some more intelligent construct like a vector or boost::array.
The C sizeof operator is evaluated at compile-time, not run-time. As written, the compiler does not have enough information to determine the size of the array.
Instead, change your function prototype. Pass in a pointer to the array as well as the length of the array.