C++ list insertion strange behavior - c++

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.

Related

Smart pointer which can change ownership at runtime (C++)

I often encounter a situation when I have complex class (e.g. implementing some numerical algorithm like Partial Differential Equation Solver) with data arrays which it can either own or bind from external context depending on use case. The problem is how to make robust destructor for such class. Simple way is to make boolean flag which indicates wheather the array is owned. E.g.
// simplest example I can think about
class Solver{
int nParticles;
bool own_position;
bool own_velocity;
double* position;
double* velocity;
// there is more buffers like this, not just position and velocity, but e.g. mass, force, pressure etc. each of which can be either owned or binded externally independently of each other, therefore if there is 6 buffers, there is 2^6 variants of owership (e.g. of construction/destruction)
void move(double dt){ for(int i=0; i<n; i++){ position[i]+=velocity[i]*dt; } }
~Solver(){
if(own_position) delete [] position;
if(own_velocity) delete [] velocity;
}
};
Naturally, this motivates to make a template wrapper around the array pointer (should I call it smart pointer ?):
template<typename T>
struct Data{
bool own;
T* data;
~Data{ if(own)delete [] T; }
};
class Solver{
int nParticles;
Data<double> position;
Data<double> velocity;
void move(double dt){ for(int i=0; i<n; i++){ position.data[i]+=velocity.data[i]*dt; } }
// default destructor is just fine (?)
};
Question:
This must be common pattern, do I reinvent a wheel here?
Is something like this in C++ standard library ? (sorry, I'm rather a physicist than a programmer)
are there some catches to think about ?
----------------------------------------
EDIT: To make clear what bind to external contex mean (as Albjenow suggested):
case 1) private/internal work array (no shared ownership)
// constructor to allocate own data
Data::Data(int n){
data = new double[n];
own = true;
}
Solver::Solver(int n_){
n=n_;
position(n); // type Data<double>
velocity(n);
}
void flowFieldFunction(int n, double* position, double* velocity ){
for(int i=0;i<n;i++){
velocity[i] = sin( position[i] );
}
}
int main(){
Solver solver(100000); // Solver allocates all arrays internally
// --- run simulation
// int niters=10;
for(int i=0;i<niters;i++){
flowFieldFunction(solver.n,solver.data.position,solver.data.velocity);
solver.move(dt);
}
}
case 2) Bind To External data array (e.g. from other class)
Data::bind(double* data_){
data=data_;
own=false;
}
// example of "other class" which owns data; we have no control of it
class FlowField{
int n;
double* position;
void getVelocity(double* velocity){
for(int i=0;i<n;i++){
velocity[i] = sin( position[i] );
}
}
FlowField(int n_){n=n_;position=new double[n];}
~FlowField(){delete [] position;}
}
int main(){
FlowField field(100000);
Solver solver; // default constructor, no allocation
// allocate some
solver.n=field.n;
solver.velocity(solver.n);
// bind others
solver.position.bind( field.position );
// --- run simulation
// int niters=10;
for(int i=0;i<niters;i++){
field.getVelocity(solver.velocity);
solver.move(dt);
}
}
Here is a simple way to do what you want without having to write any smart pointer yourself (it would be hard to get the fine details correct) or writing a custom destructor (which would mean more code and bug potential from the other special member functions required by the rule of five):
#include <memory>
template<typename T>
class DataHolder
{
public:
DataHolder(T* externallyOwned)
: _ownedData(nullptr)
, _data(externallyOwned)
{
}
DataHolder(std::size_t allocSize)
: _ownedData(new T[allocSize])
, _data(_ownedData.get())
{
}
T* get() // could add a const overload
{
return _data;
}
private:
// Order of these two is important for the second constructor!
std::unique_ptr<T[]> _ownedData;
T* _data;
};
https://godbolt.org/z/T4cgyy
The unique_ptr member holds the self-allocated data, or is empty when externally owned data is used. The raw pointer points to the unique_ptr contents in the former case, or the external content in the latter case. You could modify the constructors (or only make them accessible via static member functions like DataHolder::fromExternal() and DataHolder::allocateSelf() which return DataHolder instances created with the appropriate constructor) to make accidental misuse harder.
(Note that the members are initialized in the order they are declared in the class, not in the order of the member initializer lists, so having the unique_ptr before the raw pointer is important!)
And of course, this class cannot be copied (due to the unique_ptr member) but can be move-constructed or -assigned (with the correct semantics). Works out of the box as it should.
One solution is to separate data ownership from your solver algorithm. Having the algorithm optionally manage lifetime of its inputs isn't good design because it leads to entanglement of separate concerns. The solver algorithm should always refer to already existing data. And have another extra class that owns data, if necessary, and have lifetime no shorter than that of the algorithm, e.g.:
struct Solver {
int nParticles;
double* position;
double* velocity;
};
struct Data {
std::vector<double> position, velocity; // Alternatively, std::unique_ptr<double[]>.
template<class T>
static T* get(int size, std::vector<T>& own_data, T* external_data) {
if(external_data)
return external_data;
own_data.resize(size);
return own_data.data();
}
double* get_position(int nParticles, double* external_position) { return get(nParticles, position, external_position); }
double* get_velocity(int nParticles, double* external_velocity) { return get(nParticles, velocity, external_velocity); }
};
struct SolverAndData {
Data data;
Solver solver;
SolverAndData(int nParticles, double* external_position, double* external_velocity)
: solver{
nParticles,
data.get_position(nParticles, external_position),
data.get_velocity(nParticles, external_velocity)
}
{}
SolverAndData(SolverAndData const&) = delete;
SolverAndData& operator=(SolverAndData const&) = delete;
};
int main() {
SolverAndData a(1, nullptr, nullptr);
double position = 0;
SolverAndData b(1, &position, nullptr);
double velocity = 0;
SolverAndData c(1, nullptr, &velocity);
SolverAndData d(1, &position, &velocity);
}

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.

Finite element c++ implementation

I'm dealing with a code that is really poorly commented, since I need to expand a few functionalities I need to understand what every piece of code does in order to know if my changes will affect it.
The code is dealing with 2D mesh generation (using library Triangle for it) and solving PDEs on it.
Here is the code I don't understand:
void FiniteElement<Integrator, ORDER>::setPhiMaster()
{
Eigen::Matrix<Real,3*ORDER,1> coefficients;
for (auto i=0; i < 3*ORDER; i++)
{
coefficients = MatrixXr::Zero(3*ORDER,1);
coefficients(i) = 1;
for (auto iq=0; iq < Integrator::NNODES; iq++)
{
Real phi = evaluate_point<ORDER>(reference_,Integrator::NODES[iq],coefficients);
phiMapMaster_(i,iq) = phi;
}
}
}
In the end I would like to know what exactly is phiMapMaster_ and whats the possible use of it!
It is a method inside the template class FiniteElement, suppose ORDER=1, and Integrator:
class IntegratorTriangleP2{
public:
static const UInt ORDER = 1;
//Number of nodes
static const UInt NNODES = 3;
//Point locations
static const std::vector<Point> NODES;
static const std::vector<Real> WEIGHTS;
};
const std::vector<Real> IntegratorTriangleP2::WEIGHTS = std::vector<Real>{ {1./3, 1./3, 1./3} };
const std::vector<Point> IntegratorTriangleP2::NODES = std::vector<Point> { {Point(1./6,1./6),Point(2./3,1./6),Point(1./6,2./3)} };
(Point is the same as std::complex), and here is the method evaluate_point that takes as imput a triangle (simply 3 points counter-clockwise ordered), the point (which is internal to the triangle) and the coefficients of the Fourier basis defined on the triangle
template <>
inline Real evaluate_point<1>(const Triangle<3>& t, const Point& point, const Eigen::Matrix<Real,3,1>& coefficients)
{
Eigen::Matrix<Real,3,1> bary_coeff = t.getBaryCoordinates(point);
//getBaryCoordinates retunrs the barycentric coordinates of the point wrt the triangle t
return(coefficients.dot(bary_coeff));
}

Initialize pointer to array

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
}
};

sorting vector with 3D points by a coordinate value -- syntax

I want to sort points_vec vector as shown in the pseudocode below. I want to sort this vector, by a coordinate value like x or y or z
class A{
std:vector<double*> points_vec;
void doSomething();
}
Then, in method A::doSomething, I want sort this vector:
void A::doSomething() {
std::sort(points_vec.begin(), points_vec.end(), sortPoints());
}
Can someone please show me syntax for the sortPoints() method.. Preferably I want it to be a method of class A. this post creates a struct to do this, not sure if I should create a similar struct within the class. Is there another way to handle this?
thanks
The simplest way is to provide a functor which is used by the sort algorithm to compare two values. You can write like this:
struct Compare
{
bool operator()(double* first, double* second) const
{
//Compare points here
}
};
And use like:
std::sort(p.begin(), p.end(), Compare());
EDIT for comment by OP: Yes, this sample code compiles fine:
class A
{
public:
struct c
{
bool operator()(int a, int b) const
{
return a < b;
}
};
};
int main()
{
std::vector<int> a1;
a1.push_back(2);
a1.push_back(1);
std::sort(a1.begin(), a1.end(), A::c());
return 0;
}
You have two options for sorting: either pass a function/functor to sort or define the operator< for your class. Now, your class A seems to be more of a wrapper for a set of coordinates. So, create another class for your co-ordinates.
struct Point {
double x_, y_, z_;
Point(double x, double y, double z) : x_(x), y_(y), z_(z) {}
// just an example, you can refine the following as much as you need
bool operator<(Point const& other) {
return x < other.x;
}
};
bool sortOnY(Point const& l, Point const& r) const {
return l.y < r.y;
}
class A {
std::vector<Point> pts_;
void doSomething() {
sort(pts_.begin(), pts_.end());
}
// if sorting on y is also required, you will need
// to use a custom comparator which can be either
// a functor or a function
void doSomeOtherThing() {
sort(pts_.begin(), pts_.end(), sortOnY);
}
};
First of all - what you have will break all your points - as you'll sort by single doubles not by "points consisting of 3 doubles".
The best way to do this I think is:
Store the points as some Point3D class not a couple doubles
Define the less then operator for Point3D
Just call std::sort(points_vec.begin(), points_vec.end() );
If you'd want to sort them by in different ways that's when you'd use the sort functor and create different functors with operators() for different purposes.
I don't think this thread would be complete without a mention of Boost.Bind:
struct Point3D {
double x, y;
Point3D(double x=0., double y=0.) : x(x), y(y) {
}
};
int main() {
std::vector<Point3D> points;
points.push_back(Point3D(-1., 2.));
points.push_back(Point3D( 2., -1.));
points.push_back(Point3D(-2., 0.));
using boost::bind;
std::sort(points.begin(), points.end(),
bind(&Point3D::x, _1) < bind(&Point3D::x, _2));
// points sorted by x coord
std::sort(points.begin(), points.end(),
bind(&Point3D::y, _1) < bind(&Point3D::y, _2));
// points sorted by y coord
}
What a shame std::tr1::bind does not support that. But of course, with a C++0x compiler you'll be able to do this:
std::sort(points.begin(), points.end(),
[](Point3D const & a, Point3D const & b) { return a.x < b.x; });
If you want to sort by x or y or z, those are three different functionalities. Which coordinate to sort by is extra information which doesn't really come from std::sort. You need have an object to pass it on.
struct coord_comparison {
int coord_id; // <= critical information
bool operator()( double (*l)[3], double (*r)[3] ) {
return (*l)[ coord_id ] < (*r)[ coord_id ];
}
coord_comparison( int id ) { coord_id = id; }
};
Create this struct inside your class or outside, but it needs to be a structure and not a free function, and operator() cannot be static. Call:
std::sort(points_vec.begin(), points_vec.end(), compare_points( 1 /*for y*/) );
Sorting by all 3 coords at once:
You have
std:vector<double*> points_vec;
I'm going to presume that the double* points to an array of 3 coordinates. This is cleaner:
std:vector<double(*)[3]> points_vec;
std::sort's third argument is a functor which compares two sequence objects:
bool compare_coords( double(*l)[3], double(*r)[3] ) {
Fortunately, comparing two sequences is already coded for you by std::less:
return std::less( *l, *l + ( sizeof *l/sizeof **l ), r );
(perhaps I did more work than necessary to get the size of the array)
return std::less( *l, *l + 3, r );
}
This function may be useful outside the class, so I'd make it a free function. You need to make it static if it's going to stay inside the class.
Finally, leave off the parens when passing the function to std::sort:
std::sort(points_vec.begin(), points_vec.end(), compare_points );