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);
}
Related
I want to have a class which has a member array. The size of the array should be given when I initialize the object. I just found a way with pointers to do this. I think it is working correctly, but can you maybe tell me if this is the best way to do it or if there are any things which do not work which I haven't recognized yet?
#include <iostream>
using namespace std;
class Surface {
private:
float dx;
int N;
float* mesh_points;
public:
Surface(float, int);
~Surface();
void set_dx (float);
float get_dx();
};
Surface::Surface(float dx,int N){
this->dx = dx;
this ->N = N;
mesh_points = new float[N];
}
void Surface::set_dx (float dx) {
this->dx = dx;
}
float Surface::get_dx (void) {
return dx;
}
Surface::~Surface(){
delete[] mesh_points;
}
int main () {
Surface s(1.2,10);
s.set_dx (3.3);
cout << "dx: "<< s.get_dx() <<endl;
float mesh_points[3];
return 0;
}
can you maybe tell me if this is the best way to do it or if there are any things which do not work which I haven't recognized yet?
That'd be my take basing on existing best practices:
class Surface {
private:
std::vector<float> mesh_points;
public:
float dx;
Surface(float dx, std::size_t n);
};
Surface::Surface(float dx, std::size_t n)
: dx(dx)
, mesh_points(n)
{
}
In short, the changes made:
Got rid of manual memory management, which implies dtor as well.
Added names for parameters in declarations (really important for usability/IDEs, don't remove them!)
Got rid of superfluous accessors and made dx public.
Used ctor init lists, making the body obsolete.
Got rid of using namespace std; in lieu of explicit std:: prefix.
Changed n type to std::size_t (see comment).
Please note that the current interface doesn't allow any access to mesh_points.
Here's an alternative suggestion that allows you to keep your current implementation but is a lot safer.
class Surface {
private:
float dx;
int N;
float* mesh_points;
public:
Surface(float, int);
~Surface();
void set_dx (float);
float get_dx();
Surface(const Surface&) = delete; // new
Surface& operator=(const Surface&) = delete; // new
};
By deleting the implementation of the copy constructor and copy assignment operator you prevent your Surface objects from being copied (which would likely crash your program anyway). Any attempt to copy Surface objects will now result in a compile time error.
Only a suggestion, my first choice would always be to use std::vector.
Recently I was working on a project that involved passing arguments by value in C++ and something strange was happening when trying to access the argument fields. The code looked like this:
int main (){
int sizes[] = {2, 3};
Topology top;
top.set_dim(2); // 2D topology
top.set_sizes(sizes); // 2 rows and 3 columns
Architecture arch;
arch.set_topology(top);
}
The Topology class looks like this (it does not have a copy constructor, so I assume it will be generated automatically by the compiler and will be a shallow one, only copying the pointer address, not the data inside):
class Topology {
public:
Topology();
~Topology();
void set_dim(int);
void set_sizes(int*);
int get_dim();
int* get_sizes();
private:
int dim;
int *sizes;
};
Topology::Topology(){
}
Topology::~Topology(){
if (sizes != NULL)
delete sizes;
}
void Topology::set_dim(int dim_){
dim = dim_;
}
void Topology::set_sizes(int *sizes_){
sizes = new int[dim];
for (int i = 0; i < dim; i++){
sizes[i] = sizes_[i];
}
}
int Topology::get_dim(){
return dim;
}
int* Topology::get_sizes(){
return sizes;
}
The Architecture class is the following:
class Architecture {
public:
Architecture();
~Architecture();
void set_topology(Topology top);
private:
Parallelization p;
};
Architecture::Architecture(){
}
Architecture::~Architecture(){
}
Architecture::set_topology(Topology top){
p.set_topology(top);
}
Finally, the Parallelization class:
class Parallelization{
public:
Parallelization();
~Parallelization();
void set_topology(Topology top);
private:
};
Parallelization::Parallelization(){
}
Parallelization::~Parallelization(){
}
void Parallelization::set_topology(Topology top){
int *s = top.get_sizes();
for (int i = 0; i < top.get_dim(); i++){
std::cout << s[i] << " "; // here it prints different numbers, like the vector was never initialized [23144, 352452]
}
}
Shortly, I have a Topology object that gets passed to the Architecture and then to the Parallelization class and there I want to see the internal values from the topology sizes vector. Every time the object is passed by value the implicit copy constructor is called and copies only the dim field and the address of the sizes field, not the whole vector. I wonder why I receive different values, because the vector is still in memory, so it should print the same values.
I mention that if I implement a deep copy-constructor inside the Topology class it works just fine, or if I send the top object by reference.
Am I missing something? What could be the cause of this behavior?
I've looked for a while and none of the answers seem to fully fit my question, that or I've just hit a mental barrier.
I've made a class that has set and get methods and an output method called pairs, this works with two ints x+y and they each have set and get methods individually. I need to make a dynamic array based on the code below that can store these pairs. I'm not looking to be spoon fed I just want to know if my logic is correct and be pointed in the right direction.
class dynArray //a dynamic(ish) array class
{
public:
dynArray() : data(0), sz(0) { }
dynArray(int size) : sz(size) { data = new int[sz]; }
virtual ~dynArray() { if(data) delete [] data; } //destructor method
int& operator [] (int idx) { return data[idx]; } //operator overload!
int size() { return sz; }
private:
int * data;
int sz;
};
Pairs class
class pairs{
public:
pairs() : x(0), y(0) { }
void setX(int);
void setY(int);
void outputXY(int, int);
int getX();
int getY();
private:
int *x;
int *y;
};
void pairs::setX(int a)
{
x = &a;
}
void pairs::setY(int b)
{
y = &b;
}
int pairs::getX()
{
return *x;
}
int pairs::getY()
{
return *y;
}
void pairs::outputXY(int c, int d)
{
x = &c;
y = &d;
cout << "Number 1:" << c << " Number 2:" << d;
}
I'm very rusty with c++ so my logic has just vanished, I'm struggling to see how I would make an array that can store two ints within one element. Then i thought maybe I could make the pair class an array that stores two numbers in element 0 and 1 and then make an array of that class using the dynamic code, figuring out how to do this has stumped me though. All I really need is a helpful link or terms to be thrown at me as I really want to learn the code myself. Any help would be really appreciated, Thanks.
I would recommend using the STL library, in particular std::pair and some kind of container like std::lists or std::vectors. In order to implement some own, additional functionality, you may create your own class derived from those.
(Not enough "reputation" to post this answer as comment...)
If I correctly understood your issue, I'd suggest using a std::vector to store your elements since it will also spare you the memory management hassle
class dynArray //a dynamic(ish) array class
{
public:
dynArray() {}
dynArray(int size) { data.resize(size); /* Initialize with default-constructed elements */ }
pairs& operator [] (int idx) { return data[idx]; }
size_t size(){ return data.size(); }
private:
std::vector<pairs> data;
};
Just provide some insertion methods and you'll be good to go. Notice that the design will greatly simplify itself with the above solution.
Another solution as user236012 pointed out could be to use std::pair (specifically std::pair<int,int>) and just store the pairs in the vector.
If you intend to use the pairs class, be aware that your code is wrong:
void pairs::setX(int a)
{
x = &a; // Address of the actual parameter - address on the stack
}
therefore I'd suggest to either store plain values or use std::pair as suggested. There's really little point in storing pointers to integer values (they'd even be more expensive on many architectures).
A c-like way:
int * getPair(int idx)
{
return &data[idx*2];
}
void setPair(int idx, int * xy)
{
data[idx*2]=xy[0]; data[idx*2+1]=xy[1];
}
OK, so I recently learned that (a) std::vector uses contiguous memory by definition/standard, and thus (b) &(v[0]) is the address of that contiguous block of memory, which you can read/write to as an old-skool C-array. Like...
void printem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) std::cout << iary[i] << std::endl; }
void doublem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) iary[i] *= 2; }
std::vector<int> v;
for (size_t i=0; i<100; ++i) v.push_back(i);
int* iptr = &(v[0]);
doublem(v.size(), iptr);
printem(v.size(), iptr);
OK, so that's cool, but I want to go in the other direction. I have lots and lots of existing code like
double computeSomething(const std::vector<SomeClass>& v) { ... }
If I have a C-array of objects, I can use such code like this:
SomeClass cary[100]; // 100*sizeof(SomeClass)
// populate this however
std::vector<SomeClass> v;
for (size_t i=0; i<100; ++i) v.push_back(cary[i]);
// now v is also using 100*sizeof(SomeClass)
double x = computeSomething(v);
I would like to do that (a) without the extra space and (b) without the extra time of inserting a redundant copy of all that data into the vector. Note that "just change your stupid computeSomething, idiot" is not sufficient, because there are thousands of such functions/methods that exhibit this pattern that are not under my control and, even if they were are too many to go and change all of them.
Note also that because I am only interested in const std::vector& usage, there is no worry that my original memory will ever need to be resized, or even modified. I would want something like a const std::vector constructor, but I don't know if the language even allows special constructors for const instances of a class, like:
namespace std { template <typename T> class vector {
vector() { ... }
vector(size_t n) { ... }
vector(size_t n, const T& t) { ... }
const vector(size_t n, T*) { ... } // can this be done?
...
If that is not possible, how about a container derived off of std::vector called std::const_vector, which (a) could construct from a pointer to a c-array and a size, and (b) purposefully did not implement non-const methods (push_back, resize, etc.), so then even if the object with a typename of const_vector is not actually a const object, the interface which only offers const methods makes it practically const (and any erroneous attempts to modify would be caught at compile time)?
UPDATE: A little messing around shows that this "solves" my problem wrt Windows-implementation of std::vector:
template <typename T>
class vector_tweaker : public std::vector<T> {
public:
vector_tweaker(size_t n, T* t) {
_saveMyfirst = _Myfirst;
_saveMylast = _Mylast;
_saveMyend = _Myend;
_Myfirst = t;
_Mylast = t + n;
_Myend = t + n;
}
~vector_tweaker() {
_Myfirst = _saveMyfirst;
_Mylast = _saveMylast;
_Myend = _saveMyend; // and proceed to std::vector destructor
}
private:
T* _saveMyfirst;
T* _saveMylast;
T* _saveMyend;
};
But of course that "solution" is hideous because (a) it offers no protection against the base class deleting the original memory by doing a resize() or push_back() (except for a careful user that only constructs const vector_tweaker()) -- and (b) it is specific to a particular implementation of std::vector, and would have to be reimplemented for others -- if indeed other platforms only declare their std::vector member data as protected: as microsoft did (seems a Bad Idea).
You can try reference-logic storing introduced in C++11 with std::reference_wrapper<>:
SomeClass cary[100];
// ...
std::vector<std::reference_wrapper<SomeClass>> cv;
cv.push_back(cary[i]); // no object copying is done, reference wrapper is stored
Or without C11, you can create a specialization of such template class for bytes - char. Then for the constructor from char* C-array you can use ::memcpy: which unfortunately will then use twice as much memory.
::memcpy(&v[0], c_arr, n);
Something like this:
template <typename T> class MyVector : public std::vector<T> {
};
template <> class MyVector<char> : public std::vector<char> {
public:
MyVector<char>(char* carr, size_t n) : std::vector<char>(n) {
::memcpy(&operator[](0), carr, n);
}
};
What I would recommend - replace all C-arrays to vectors where possible, then no extra copying will be needed.
I'm using a 2D matrix in one of my projects. It's something like it is suggested at C++ FAQ Lite.
The neat thing is that you can use it like this:
int main()
{
Matrix m(10,10);
m(5,8) = 106.15;
std::cout << m(5,8);
...
}
Now, I have a graph composed of vertices and each vertex has a public (just for simplicity of the example) pointer to 2D matrix like above. Now I do have a pretty ugly syntax to access it.
(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...
Probably I'm missing some syntactic sugar here due to my inexperience with operator overloading. Is there a better solution?
Consider using references instead of pointers (provided, it can't be null and you can initialize in the constructor).
Consider making a getter or an instance of a matrix wrapper class for a vertex that returns a reference to 2D matrix (provided, it can't be null).
sampleVertex.some2DTable()(0,0) = 0;
sampleVertex.some2DTableWrap(0,0) = 0;
However, to me it sounds like a non-issue to justify going through all the trouble.
If you have a pointer to a Matrix, e.g. as a function parameter that you can't make a reference (legacy code, e.g.), you can still make a reference to it (pseudo code):
struct Matrix {
void operator () (int u, int v) {
}
};
int main () {
Matrix *m;
Matrix &r = *m;
r (1,1);
}
You're basically limited to (*sampleVertex.some2DTable)(0,0). Of course, if you don't need reseating, why not store the actual values in the matrix instead?
Alternatively, make the pointer private and make an accessor (note: the following examples assume a matrix of EntryTypes):
Matrix& Vertex::GetTableRef()
{
return *some2DTable;
}
// or
Matrix::EntryType& Vertex::GetTableEntry(int row, int col)
{
return (*some2DTable)(row,col);
}
// way later...
myVertex.GetTableRef()(0,0) = 0;
// or...
myVertex.GetTableEntry(0,0) = 0;
Or, just define an inline function to do this for you if you can't change the class Vertex:
// in some header file
inline Matrix& GetTableRef(Vertex& v)
{
return *v.some2DTable;
}
// or you could do this
inline Matrix::EntryType& GetTableEntry(Vertex& v, int row, int col)
{
return (*v.some2DTable)(row, col);
}
// later...
GetTableRef(myVertex)(0, 0) = 0;
// or
GetTableEntry(myVertex, 0, 0) = 0;
Finally, don't forget that you don't have to use operator overloading. STL collections implement an at() member function, which is checked, as opposed to operator[] which is unchecked. If you don't mind the overhead of bounds checking, or if you just want to be nonstandard, you could implement at() and then just call myVertex.some2DTable->at(0,0), saving a bit of a syntactic headache altogether.
There is no C++ syntactic sugar that will ease the pain of what you describe:
(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...
In this situation, I would either have the graph return a reference instead of a pointer, or have the matrix define a function which calls the operator():
inline matrixType &Matrix::get( int x, int y ){ return operator()(x,y); }
Then, the syntax isn't quite as ugly for the vertex example:
sampleVertex.some2DTable->get(0,0) = 0;
I would add a function that returns you a ref like rlbond recommends. For a quick fix or if you don't have control over the source of it, i would go with this:
sampleVertex.some2DTable[0](0,0) = 0; // more readable
That's actually equivalent, because the following holds if a is a pointer to a defined class:
*a == *(a + 0) == a[0]
See this long discussion on comp.lang.c++ about that same problem with good answers.
This is the best way without changing your code:
//some2DTable is a pointer to a matrix
(*sampleVertex.some2DTable)(0,0)
You could also instead make some2DTable a reference to a matrix instead of a pointer to a matrix. Then you would have simplified syntax as in your first code sniplet.
//some2DTable is a reference to a matrix instead of a pointer to a matrix
sampleVertex.some2DTable(0,0)
Or you could keep some2DTable a pointer to a reference and simply store a reference variable to it and use that in the context of your code block.
I'd change the way you get hold of "sampleVertex.some2DTable" so it returns a reference.
Either that or create the reference yourself:
Matrix& m = *sampleVertex.some2DTable;
m(1,2) = 3;
I don't know if it's worth the trouble, but you could do:
class MatrixAccessor {
private:
Matrix2D* m_Matrix;
public:
MatrixAccessor(Matrix2D* matrix) : m_matrix(matrix) { }
double& operator()(int i, int j) const { return (*m_Matrix)(i,j); }
Matrix2D* operator->() const { return m_Matrix; }
void operator=(Matrix2D* matrix) { m_Matrix = matrix; }
};
Provided the original operator() returns a reference (as it is in many matrix classes).
Then you provide that MatrixAccessor in your vertex class:
class Vertex {
Matrix2D* myMatrix;
public:
MatrixAccessor matrix;
Vertex(Matrix2D *theMatrix) : myMatrix(theMatrix), matrix(theMatrix) { }
};
Then you can write:
Vertex v;
v.matrix(1,0) = 13;
v.matrix->SomeOtherMatrixOperation();
EDIT
I added const keywords (thanks to #phresnel for bringing up the topic) in order to make the solution semantically equivalent to a solution only presenting a public Matrix2D-pointer.
An advantage of this solution is that constness could be transferred to the matrix object by adding two non-const versions of the operator()() and operator->() (i.e. the matrix cannot be modified on const vertices) and changing the const ones to return a const double& and const Matrix2D* respectively.
That would not be possible when using a public pointer to the matrix object.
You could implement Matrix::operator (int,int) by calling a member function and use that one directly when dealing with pointers.
class Matrix
{
public:
float ElementAt( int i, int j ) const { /*implement me*/ }
float operator() ( int i, int j ) const { return ElementAt( i, j ); }
...
};
void Foo(const Matix* const p)
{
float value = p->ElementAt( i, j );
...
}
void Bar(const Matrix& m)
{
float value = m(i,j);
}