Initialize pointer to array - c++

I am trying to initialize pointer to struct array in my class constructor but it do not working at all...
class Particles {
private:
struct Particle {
double x, y, z, vx, vy, vz;
};
Particle * parts[];
public:
Particles (int count)
{
parts = new Particle [count]; // < here is problem
}
};

Remove those [] from declaration. It should be
Particle *parts;
Using C++, you can use benefits of std::vector:
class Particles {
// ...
std::vector<Particle> parts;
public:
Particles (int count) : parts(count)
{
}
};

Particle * parts[];
This is an array of pointers. To initialise this, you would need to loop through the array, initialising each of the pointers to point at a dynamically allocated Particle object.
You probably want to just make parts a pointer:
Particle* parts;
The new[] expression returns a pointer to the first element of the array - a Particle* - so the initialisation will work just fine.

Try this:
class Particles {
private:
struct Particle {
double x, y, z, vx, vy, vz;
};
Particle * parts;
public:
Particles (int count)
{
parts = new Particle [count]; // < here is problem
}
};

Related

Why does this throw a SIGSEGV? (Heap-allocated std::array)

I'm looking to build a 1D std::array of structs, each of whose size is 16 bytes. The 1D array is a flattening of a class representing a 3D array (basically an std::array wrapper that has some 3D specific operators and other fluff). My first attempt is an array of size 256 x 256 x 32, so roughly 35MB, which throws a SIGSEGV error.
A simplified example of everything looks like this:
Structs.cpp
struct Coord {
int x;
int y;
int z;
Coord() { }
Coord(int x_, int y_, int z_) { x = x_; y = y_; z = z_; }
}
int TR (int arg) {
// ... Some transformation
}
struct MyStruct {
Coord position;
int terrain;
MyStruct() { }
MyStruct(int x_, int y_, int z_, int terrain_) {
terrain = terrain_;
position = Coord(TR(x_), TR(y_), TR(z_));
}
}
ArrayWrapper.hpp
#include <array>
template <typename T, int HSIZE, int VSIZE> struct ArrayWrapper {
private:
std::array<T, HSIZE*HSIZE*VSIZE> narray;
public:
void set(T obj, int x, int y, int z) {
narray[x + z*HSIZE + y*HSIZE*HSIZE] = obj;
}
T& operator() (int x, int y, int z) {
return narray.at(x + z*HSIZE + y*HSIZE*HSIZE);
}
CoordinateMap.cpp
#include "ArrayWrapper.hpp"
#include "Structs.cpp"
const int HSIZE = 256;
const int VSIZE = 32;
class CMap {
private:
ArrayWrapper<MyStruct, HSIZE, VSIZE>* coords_ = new ArrayWrapper<MyStruct, HSIZE, VSIZE>;
ArrayWrapper<MyStruct, HSIZE, VSIZE> coords = *coords_;
public:
// ... Getter, setter, and a bunch of other methods,
~CMap() { delete coords; }
}
If I anywhere try to say CMap something; I get a SIGSEGV. I know that the stack is relatively small, so I'm attempting to allocate this structure on the heap by using new. Many people (on this site and others) say "Finding a large range of contiguous memory is difficult, even if it's on the heap," but don't give an indication of what a reasonable expectation of the size of contiguous memory is. I would think 32MB in a modern-day computer is doable.
What might be throwing a Seg. fault here?
ArrayWrapper<MyStruct, HSIZE, VSIZE> coords = *coords_;
Should be...
ArrayWrapper<MyStruct, HSIZE, VSIZE>& coords = *coords_;
... which makes sense. The 1st line is making a copy of coords_' reference, which, in this case, defeats the purpose of using new, since that copy is put on the stack.

Replacing old C style arrays with modern C++ STL data structures

I implemented a simple class for n-body simulations in C++. However, the class uses a lot of old C style arrays which I want to replace with data structures that the STL offers.
Here is the relevant part of my code that I want to improve:
struct Particle{
double m; // mass
double x[DIM]; // position
double v[DIM]; // velocity
double F[DIM]; // force
};
class Nbody {
private:
const unsigned int n; // number of particles
const double dt; // step size
const double t_max; // max simulation time
std::vector<Particle> p;
public:
~Nbody(){};
Nbody(unsigned int n_, double dt_, double t_max_);
};
Nbody::Nbody(unsigned int n_, double dt_, double t_max_)
: n{n_}, dt{dt_}, t_max{t_max_} {
p = new std::vector<Particle> [n];
}
I tried to use std::vector<Particle>. But how do I in this case initialize n particles correctly? My current approach does not work and the compiler throws many errors. How do I do it correctly?
p is not a pointer. p is declared as a vector.
Rewrite the constructor definition like
Nbody::Nbody(unsigned int n_, double dt_, double t_max_)
: n{n_}, dt{dt_}, t_max{t_max_}, p( n_ ) {
}
In this case the vector p is initialized as a vector having n elements that are value initialized.
Also in the definition of the structure Particle you could substitute the arrays to objects of the type std::array<double, DIM>. Also it is better to make the constant DIM either as enumerator of the structure or as a static data member of the structure/
new std::vector<Particle> [n] dynamically allocates an array of n empty vectors and produces a pointer to the first one.
That is not the same as a vector with n elements.
You should use the initialiser list:
Nbody::Nbody(unsigned int n_, double dt_, double t_max_)
: n{n_}, dt{dt_}, t_max{t_max_}, p{n_}
{
// Empty.
}
Assuming that n tracks the number of particles, you can get rid of it and use p.size() instead.
Initialisation of the particles themselves should be added to Particle.
struct Particle{
double mass = 0.0;
double position[DIM] = {};
double velocity[DIM] = {};
double force[DIM] = {};
};
or
struct Particle{
double mass = 0.0;
std::array<double, DIM> position;
std::array<double, DIM> velocity;
std::array<double, DIM> force;
};
To change the size of a vector, you can use:
p.resize(n);
All new elements will be default-constructed, which in this case means they will contain garbage values.

C++ private class dynamic n-dimensional array

I've been looking all around StackOverlow for an answer but i didn't find one so i hope it isn't duplication of any post around here.
so, i have the next problem.
lets say i have the next 2 classes: Rectangle (Which is built from another class but it doesn't concern us currently)
and Grid.
with they following constructors:
(Point Constructor for Rectangle private topLeft and bottomRight):
Point::Point(int x, int y) {this->x = x; this->y = y;}
(Rectangle Constructor and Class)
class Rectangle
{
public:
Rectangle(int l, int u, int w, int h, int color);
//int getColor() const;
//void setColor(int color);
//bool contains(const Point &p) const;
//void print() const;
private:
const Point topLeft, bottomRight;
int color;
};
Rectangle::Rectangle(int l, int u, int w, int h, int color) :
topLeft(l, u),
bottomRight(l + w, u + h)
{ this->color = color; }
(Grid Constructor and Class) (Lets assume I don't want to initialize the values of Rectangle in Grid just allocate them in memory)
class Grid
{
public:
Grid(int tileW, int tileH, int width, int height, int color);
//~Grid();
//Rectangle& getRectAt(const Point &p);
//void print() const;
private:
int count;
Rectangle **recs;
};
Grid::Grid(int tileW, int tileH, int width, int height, int color)
{
int index, index_c=0;
recs = new Rectangle *[width];
for (int index = 0; index < width; index++)
{
recs[index] = new Rectangle[index];
}
}
so, as you can understand i have problem in Grid constructor with the following Error
(Error 1 error C2512: 'Rectangle' : no appropriate default constructor available.)
but i just cant understand why it wont work, I've been suggested to allocate the Recs double pointer as 1 dimensional array (Array with the length of Width*Height) but what if Recs was 4 dimensional array ? How could you flat it properly and then index around the 4-dimensional array without having a headache calculating the index of each cell in the array.
another thing, we know that if it was int** and not recs** it would work perfectly
int **foo;
int height,width;
foo = new int* (height);
for (int index = 0; index<height; ++index)
foo[index] = new int[width];
so i just keep missing the way of doing n-dimensional arrays in C++.
The line recs[index] = new Rectangle[index]; tries to call Rectangle's default constructor index times. If you want to create multiple objects at once, you probably want to add default ctor and simple setter method to your Rectangle class
class Rectangle
{
public:
Rectangle(int l, int u, int w, int h, int color);
Rectangle() = default;
void set(int l, int u, int w, int h, int color);
private:
const Point topLeft, bottomRight;
int color;
};
Then, in creation loop:
for (int index_w = 0; index_w < width; index_w++)
{
recs[index_w] = new Rectangle[height]; //see note below
for (int index_h = 0; index_h < height; index_h++)
recs[index_w][index_h].set(/* some math with width, height and loop variables*/, color);
}
Note: I have changed index to height, because you want to create 2D array, so the total grid size is height * width. With index length in creation, you would create triangle-shaped grid instead (and more over, the first loop iteration would be recs[0] = new Rectangle[0] - a zero-length array).
As user Macro A mentioned, consider using std::vector<Rectangle> instead of raw pointers (2D array would be std::vector<std::vector<Rectangle>>)
Also, consider changing your design, because currently you are creating a grid H x W of Rectangle objects, where all points (except first/last) are duplicated across adjacent rectangles (each point is upper-left corner of one rectangle, upper-right corner of another, bottom-left...).
I propose a Grid class that holds 2D array of ints and has a method Rectangle getRectangle(int x, int y) which would return appropriate set of 2 points. Modyfying such Grid class would be much easier, and you wouldn't have to iterate over all Rectangles, just ints
You could use a placement new : you initially reserve enough place to store the array of objects, then individually construct them each in its own place.
In your code, it could become (more or less):
for (int index = 0; index < width; index++)
{
// first simple allocation for the array
recs[index] = (Rectangle *) malloc(sizeof(Rectangle) * height);
for (int j=0; j<height; j++) {
// individually build each rectangle in place
new(&recs[index][j]) Rectangle(index*tileW, j*tileH, tileW, tileH, color);
}
}
This is intended to do exactly what you need : build arrays of non default constructible objects.
Unrelated: as you use raw pointers and allocated arrays, do not forget to correctly free everything. Using std::vectors could save you from that...
You get error C2512 because you don't have a default constructor in Rectangle. The only constructor you have in Rectangle is parameterized, while a default constructor has the requirement that it must be callable without additional arguments provided.
Looking at the line recs[index] = new Rectangle[index];, you see there are no arguments for the 5 parameters the constructor accepts. For that line to compile, you need to create a default constructor either with a new constructor with the signature Rectangle() or default arguments for the parameters in your parameterized constructor, for example Rectangle(int l = 0, int u = 0, int w = 0, int h = 0, int color = 0);.
If you want to allocate the memory, you should create the default constructor and use std::vector<Rectangle> which you initialize with a size. Then you can later replace the objects by use of a copy-constructor, as shown in this example: http://ideone.com/KnUBPQ
As for creating an n-dimensional array, you've explicitly limited it to a two-dimensional array with your Rectangle and Point classes. If the array is going to be n-dimensional, your points need to be n-dimensional too:
template<int dimensions>
class Point
{
std::array<int, dimensions> coords;
...
};
or
class Point
{
std::vector<int> coords;
...
};

C++ list insertion strange behavior

I have a class called Particle, and another called ParticleList, which is essentially a List of Particles plus some other functions. I'm noticing some strange behavior when I try to insert a new particle into ParticleList and I'm wondering why that is happening. The classes are defined as:
class Particle {
public:
// Particle data members
int index;
vector<double> r_last;
vector<double> r;
vector<double> v;
double m;
double q;
Particle(int i, double m, double q, int ndim) :
index(i), m(m), q(q) {
r_last.resize(ndim,0);
r.resize(ndim,0);
v.resize(ndim,0);};
Particle() { };
Particle(const Particle& p);
}
and
class ParticleList : public list<Particle> {
public:
int highestIndex;
size_t numParticles;
ParticleList() {highestIndex = 0; numParticles=0;}
/*below are functions that call the List<Particle>::push_back()
and List<Particle>::push_front() functions and increment numParticles*/
void push_back(const Particle& p);
void push_front(const Particle& p);
//some more member functions here
};
Definition of push_back and push_front:
void ParticleList::push_back(const Particle &p) {
numParticles ++;
list<Particle>::push_back(p);
}
void ParticleList::push_front(const Particle &p) {
numParticles ++;
list<Particle>::push_front(p);
}
The trouble comes in when I try to insert a particle as follows:
ParticleList newParticleList;
Particle newParticle(1, 0.5, 0.5, 2);
/*creates a particle with index 1, mass and charge 0.5, and 2 dimensions.
Variables r, r_last and v are set to vectors {0,0}*/
for (int i=0;i<nDim;i++)
newParticle.r[i]=0.5 //just changed newParticle.r, everything else still {0,0}
newParticleList.push_back(newParticle);
For some reason, when I do the last step, the value of the r_last vector for the list member that just got inserted changes to the value of the r vector. So if I print out newParticle.r_last, that'd give me {0,0}, but if print out the member of the list:
auto ii=newParticleList.end();
ii--;
Particle p=*ii;
for(int i=0;i<p.size();i++)
cout<<p.r_last[i];
I get {0.5,0.5}, which is the value of p.r. If I change the r vector after this point, it doesn't affect the value of r_last...only when I push_back does it create this effect. I've tried different computers, removed optimization flags, tried push_front and insert, and it's still the same behavior. Does anyone have ideas on what might be causing this?
Thank you!
Siddharth
Here Particle p=*ii; you create a copy of Particle object. So check your copy constructor Particle(const Particle& p);. May be it incorrectly copies p.r into p.r_last.

a nicer way to create structs in a loop

I haven't coded in C++ in ages. And recently, I'm trying to work on something
involving structs. Like this
typedef struct{
int x;
int y;
} Point;
Then in a loop, I'm trying to create new structs and put pointers to them them in a list.
Point* p;
int i, j;
while (condition){
// compute values for i and j with some function...
p = new Point;
p* = {i, j}; //initialize my struct.
list.append(p); //append this pointer to my list.
}
Now, my question is it possible to simplify this? I mean, the pointer
variable *p outside of the loop and calling p = new Point inside the loop.
Isn't there a better/nicer syntax for this?
Sure:
Point * p = new Point;
You should probably also give your Point class a constructor:
struct Point { // note no need for typedef
int x;
int y;
Point( int ax, int ay ) : x( ax ), y( ay ) {}
};
so that you can say:
Point * p = new Point( i, j );
You may also want to make your list a list of Point values, rather than pointers, in which case you can avoid using dynamic allocation with new - always something to be avoided wherever possible in C++.
The struct can have a constructor like:
struct Point{
Point(int ax, int ay):x(ax), y(ay){}
int x;
int y;
};
and then the function can look like:
int i, j;
while (condition)
{
list.append(new Point(i,j));
}
As structs are classes with public members by default, you could even create a constructor within the struct and initialize your point object within the loop like this:
Point* p = new Point(i,j);
I would venture a guess that it is extremely unlikely you really need to allocate something like a Point dynamically.
Most likely you want to add a constructor and store them by value:
list<Point> list;
list.append(Point(x, y));
I recommend the Factory approach. Assuming that "Point" will be the base class of many objects, you can have a "Factory" that would return pointers.
Ex:
struct Point
{
Point(int mx, int my):x(mx),y(my) {}
int x;
int y;
};
// Circle, Polygon, etc.
class Factory
{
public:
static Point *getPoint(int mx, int my) { return new Point(mx, my); }
// Circle, Polygon, etc
};
Then in code someplace:
while(cond)
{
list.append(Factory::getPoint(i, j));
}