I have the following
std::vector<Cube> well = vector<Cube>();
createCube(well, x, y, z, id);
Later I try to insert a Cube into the vector like this,
void Viewer::createCube(std::vector<Cube> vec, int x, int y, int z, int id) {
float rgb[] = {0.0f, 0.0f, 1.0f};
vec.push_back(Cube(QMatrix4x4(), -1));
int loc = vec.size() - 1;
std::cout << "loc:" << loc << std::endl;
vec.at(vec.size() - 1).matrix.translate(x,y,z);
}
I get output loc = 0.
Why is it not the new Cube to my Vector?
You are passing the vector by value to the createCube function; that means that your vector is copied and then the element is added to the new vector and not to the original one. You can fix it by changing your method signature to:
void Viewer::createCube(std::vector<Cube>& vec, int x, int y, int z, int id)
Related
I've been this trying for several hours now. I cannot find a way to pass a fixed-size array to an operator. I found some stuff here on stackoverflow and tried it that way, as you can see in my code, but it won't work at all. The task is, that the code shouldn't be compiled if the array is not of size 3, that means, that if the array is of size 2 or size 4, that I should get a compile error. Can someone tell me how to implement this? Thanks in advance! :)
class Vec3 {
private:
int x, y, z;
public:
Vec3 (int x, int y, int z) : x(x), y(y), z(z) {}
int getX () const
{
return x;
}
int getY () const
{
return y;
}
int getZ () const
{
return z;
}
};
Vec3 operator+(Vec3 &vec, int (*arr)[3]) {
int x,y,z;
x = vec.getX() + (*arr)[0];
y = vec.getY() + (*arr)[1];
z = vec.getZ() + (*arr)[2];
Vec3 result(x,y,z);
return result;
}
int main () {
Vec3 v1 (1,2,3);
int v3 [] = {2,4,6};
cout << "v1 + v3 = " << v1 + v3 << endl;
return 0;
}
You got the syntax slightly wrong. Instead of
Vec3 operator+(Vec3 &vec, int (*arr)[3])
it must be
Vec3 operator+(Vec3 &vec, int (&arr)[3])
to pass the array by reference. And you can drop the value-of-operator (*) before the array-access, so you end up with
Vec3 operator+(Vec3 &vec, int (&arr)[3]) {
int x,y,z;
x = vec.getX() + arr[0];
y = vec.getY() + arr[1];
z = vec.getZ() + arr[2];
Vec3 result(x,y,z);
return result;
}
Use template to do it:
template<size_t N>
Vec3 operator+(Vec3 &vec, int (&arr)[N]) {
static_assert(N==3,"wrong size of array");
// the rest of the code , small fix: arr[0] etc
static assert will be triggered when N is not equal to 3.
Demo
I have this structure:
struct Vertex {
Vertex(float px, float py, float pz,
float nx, float ny, float nz,
float tx, float ty) : position(px, py, pz),
normals(nx, ny, nz),
texCoords(tx, ty) {}
XMFLOAT3 position;
XMFLOAT3 normals;
XMFLOAT2 texCoords;
};
and I need to fill an array of that with some vectors:
std::vector<XMFLOAT3> positions;
std::vector<XMFLOAT3> normals;
std::vector<XMFLOAT2> texCoords;
The length of the array is given by
int numVertices;
I' d like to fill the array of struct Vertex with the vectors given. How can I do that?
I tried to initialize the array in this way:
Vertex points[numVertices];
but that var does not have a constant value.
Thank you for your help.
std::vector is the best option to create a dynamic array.
It takes care of memory management for you.
You can access the contents of the array using std::vector::data, std::vector::operator[], std::vector::iterator.
You can process each element of a std::vector using a range-for loop.
Instead of
Vertex points[numVertices];
use
std::vector<Vertex> points(numVertices);
If you must use raw arrays, you can try this. Assuming XMFLOAT3, XMFLOAT2 is something like follows:
struct XMFLOAT3 {
XMFLOAT3(float x, float y, float z) : _x(x), _y(y), _z(z) {};
float _x;
float _y;
float _z;
};
struct XMFLOAT2 {
XMFLOAT2(float x, float y) : _x(x), _y(y) {};
float _x;
float _y;
};
define an init function to initialize Vertex array by dynamically allocating and initializing the elements as:
Vertex **
initVertex(int numVertices)
{
Vertex **points = new Vertex *[numVertices];
for (int i = 0; i < numVertices; ++i) {
points[i] = new Vertex(positions[i]._x, positions[i]._y, positions[i]._x,
normals[i]._x, normals[i]._y, normals[i]._z,
texCoords[i]._x, texCoords[i]._y);
}
return points;
}
You can use Vertex **points = initVertex(numVertices) and dereference each element.
If you must have Vertex *points then you can use this function to create the initialized array of Vertices:
Vertex *
initVertex2(int numVertices)
{
char *points_buf = new char[sizeof(Vertex) * numVertices];
Vertex *points = reinterpret_cast<Vertex *>(points_buf);
for (int i = 0; i < numVertices; ++i) {
new (points_buf + i * sizeof(Vertex))
Vertex(positions[i]._x, positions[i]._y, positions[i]._x,
normals[i]._x, normals[i]._y, normals[i]._z,
texCoords[i]._x, texCoords[i]._y);
}
return points;
}
And call it Vertex *points = initVertex2(numVertices) and use array indexing to access each element.
Please take a look at the code below:
#include <iostream>
using namespace std;
int main(){
char matrix[2][2][2];
return 0;
}
int getMatrixData(char matrix[][2][2], int x, int y, int z) {
return matrix[x][y][z];
}
When matrix 3d array passed in as a parameter into a function, why is it ok not to specify the first [] size? How this missing dimension can be explained?
Your code is syntactically incorrect. Assuming you meant int getMatrixData(char matrix[][2][2], int x, int y, int z).
When you pass array arguments to function, array decays to pointer to first element (type char [2][2] in this case).
Now some syntax of array and pointer are similar so you don't find much difference.
When multidimensional array is passed, for example 3d in your case, it can be seen as array of 2-d arrays. So you need to give the type of each element char [2][2] in your case and you can skip the dimension of final array as it will decay to pointer anyway. char [2][2] is the information compiler needs to compute the offset of each element.
offset of matrix[x][y][z] = base address of matrix +
x * sizeof(char [2][2]) +
y * sizeof(char [2]) +
z
If you don't pass the dimensions of initial element, compiler can't resolve sizeof in above equation. Passing skipped dimension is optional.
In c++ I would use multidimensional arrays in a different way. There are many topics on the internet about it.
This topic explains how you could do it using a char***. E.g.:
char getMatrixData(char*** matrix, int x, int y, int z)
{
return matrix[x][y][z];
}
int main()
{
char ***matrix = new char**[2];
for (auto i = 0; i < 2; i++)
{
matrix[i] = new char*[2];
for (auto j = 0; j < 2; j++)
{
matrix[i][j] = new char[2];
}
}
getMatrixData(matrix, 1, 1, 1);
// N.B.! you should normally free the memory using delete []!!
// But in this case the program ends, so the memory is freed anyhow.
return 0;
}
But you could also use the std::vector type
#include <vector>
using std::vector;
using CharVector1D = vector<char>;
using CharVector2D = vector<CharVector1D>;
using CharVector3D = vector<CharVector2D>;
char getMatrixData(CharVector3D const& matrix, int x, int y, int z)
{
return matrix[x][y][z];
}
int main()
{
CharVector3D matrix(2, CharVector2D(2, CharVector1D(2)));
getMatrixData(matrix, 1, 1, 1);
return 0;
}
However, c++ is supposed to be an object oriented programming language. So it is probably better to define an matrix object.
#include <vector>
using std::vector;
template <class T>
class Matrix3D
{
private:
size_t _sizeX;
size_t _sizeY;
size_t _sizeZ;
vector<T> _data;
public:
Matrix3D(size_t const x_size, size_t const y_size, size_t const z_size)
: _sizeX(x_size)
, _sizeY(y_size)
, _sizeZ(z_size)
, _data(vector<T> (x_size*y_size*z_size))
{}
T GetData(size_t const x, size_t const y, size_t const z) const
{
return _data.at(x + (_sizeX * (y + (_sizeY * z))));
}
};
int main()
{
Matrix3D<char> matrix(2, 2, 2);
matrix.GetData(1, 1, 1);
return 0;
}
How can I convert the following class to a fixed-length float array?
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
float x, y, z;
};
For example, I would like to use it like so:
Vertex v(0, 1, 0);
float arr[3] = v; // How to convert here?
Thanks!
Edit:
I should have added some background information before posting this question.
The reason why I'm using C-style arrays is because I want to combine the high level vertex objects into a vertex array for rendering with OpenGL, which as far as I know requires a collection of raw arrays (float[3]) or structs.
For that purpose I think user2079303's answer is the best option. However, if a more elegant solution exists that would be even better. :)
#include <iostream>
#include <array>
using namespace std;
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3>() const {
return {x,y,z};
}
/* See #user2079303's answer for a compile-time check of the array dimension */
void fillArray(float arr[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
float x, y, z;
};
int main() {
Vertex v(1,1.4,2);
array<float, 3> arr = v;
float arr2[3];
v.fillArray(arr2);
for (int i = 0; i < 3; i++) {
cout << arr[i] << " " << arr2[i] << endl;
}
return 0;
}
Live Demo
std::array is as efficient as using a C-style array, no performance is lost. You can also use std::vector instead.
You can't just return and copy an array, even in C. That's why if you absolutely want to use a C array, you have to have a function like fillArray.
A class cannot be convertible to a (raw) array, because the cast operator would have to return an array, which is not allowed in c++. Furthermore, arrays cannot be copy-initialized anyway.
What you can do is define an array, and pass it to a function that populates the array according to the contents of an object:
void Vertex::fill_arr(float (&arr)[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
// usage
Vertex v(1, 2, 3);
float arr[3];
v.fill_arr(arr);
Another option is to use std::array which can be returned and copy-initialized normally.
You have many options, and it which you choose depends a lot on context. Here are four different ways to "convert" your vertex:
class Vertex
{
public:
Vertex(float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3> () const {
return {x, y, z};
}
array<float, 3> array_copy() const {
return {x, y, z};
}
unique_ptr<float[]> c_array_copy() const {
return unique_ptr<float[]>(new float[3]{ x, y, z });
}
void copy_into(float in[3]) const {
in[0] = x;
in[1] = y;
in[2] = z;
}
float x, y, z;
};
First, you can just cast the class using the () operator:
cout << "Direct access" << endl;
auto as_array = (array<float, 3>)vertex;
cout << as_array[0] << as_array[1] << as_array[2] << endl;
Second, you can let copy semantics to some work for you with array_copy():
cout << "Get a copy" << endl;
auto as_copy = vertex.array_copy();
cout << as_copy[0] << as_copy[1] << as_copy[2] << endl;
Third, you can get a more c-style array copy with a unique pointer to a dynamically allocated array:
cout << "Get a c-style copy" << endl;
auto as_c_copy = vertex.c_array_copy();
cout << as_c_copy[0] << as_c_copy[1] << as_c_copy[2] << endl;
Finally, you can copy into an out-parameter:
cout << "Copy onto an out-parameter" << endl;
float copied[3];
vertex.copy_into(copied);
cout << copied[0] << copied[1] << copied[2] << endl;
As I say, which you choose really depends on context and performance requirements.
Note that in no case can you just return a c-style array.
You can define a conversion operator to construct your array. Also I would suggest using a std::array instead of a raw array.
#include <array>
class Vertex
{
public:
Vertex(float x = 0.0f, float y = 0.0f, float z = 0.0f)
: x(x), y(y), z(z)
{}
float x;
float y;
float z;
operator const std::array<float, 3>() const
{
return {x, y, z};
}
};
int main()
{
Vertex v(0.0f, 1.0f, 0.0f);
std::array<float, 3> arr = v;
}
I want to make a 2d, 3 by 3 ,array like this:
double *array;
void setArray(double x, double y, double z){
array = {{x,0,0},
{0,y,0},
{0,0,z}};
}
I read some posts suggested something like this:
double **array = new double*[3];
void setArray(double x, double y, double z){
array[0] = new double*[3];
array[0][0] = x;
array[0][1] = 0;
array[0][2] = 0;
...
if there any method I can set a 2d array directly using values {{x,0,0},{0,y,0},{0,0,z}}?
Thanks in advance.
If you want to use lists like {{x,0,0},{0,y,0},{0,0,z}}, you should use arrays with hard-coded size:
double *array; // no good
double array[3][3]; // OK
Fill them with copying:
void setArray(double x, double y, double z){
double temp[3][3] = {{x,0,0},
{0,y,0},
{0,0,z}};
memcpy(&array, &temp, sizeof(array));
}
If you don't need jagged array, and the size is known at design time you can use this syntax to declare it:
double array[3][3];
However, if you want to use an initialisation list, you could do it like this:
typedef double Array[3][3];
Array& array(double x = 0.0, double y = 0.0, double z = 0.0) {
static double array_[3][3] = {{x,0,0},{0,y,0},{0,0,z}};
return array_;
}
// init:
array(4,5,8);
// access:
array()[0,2];