How to best modify a group of member objects the same way? - c++

Maybe I'm being to picky, but I would like to have your opinion on how to best code something like this (my problem is much more complicated but it can be simplified like this):
class A
{
public:
A ();
A (const size_t dim0, const size_t dim1);
void set_is_x_allocated (const bool);
void set_is_y_allocated (const bool);
void set_is_z_allocated (const bool);
private:
void allocate (vector<vector<double>> &) const; ??
size_t dim0;
size_t dim1;
bool is_x_allocated;
bool is_y_allocated;
bool is_z_allocated;
vector<vector<double>> x;
vector<vector<double>> y;
vector<vector<double>> z;
};
When the dimensions are given, I would like to allocate x, y, z the same way (depending on how the booleans is_x/y/z_allocated are set). The solutions I have are those at the moment:
Solution 1: Create an allocate function like above, and call if (is_x_allocated) allocate (x); etc.
Pros: x, y, z will be allocated the same way -> easier to spot errors, to modify the code if a third dimension comes in in the future.
Cons: as allocate can be used for any other vector<vector<double>>, should it be const or not?
Solution 2: Create an allocate_x (), allocate_y (), allocate_z (), call if (is_x_allocated) allocate_x();
Pros: It's adapted to the situation and allocate_x/y/z are definitely non-constant.
Cons: I have to copy the allocation code 3 times. I might make some mistakes + the code will be more complicated to modify if a 3rd dimension comes in for example.
How would you code this in an effective way? Maybe a lambda function inside a void allocate () function, but I feel like this would be making a too big deal of what it really is...

Related

To const or not to const?

I'm writing a matrix class, which will have some methods which revolve around matrices like multiplication and inverses and the things of the sort. I understand it's C++ convention to make as much things as you can (especially member functions) constant, and I would like to know whether or not it's reasonable to make my rows an columns constant. This is my structure for the class:
#pragma once
#include <vector>
#include <string>
namespace Math {
class Matrix
{
private:
//Variable initialization
using data_type = double;
const std::vector<std::vector<data_type>> m_rows;
//I know this part isn't required but I'm doing it as a sort of code-shortener
const int m_m, m_n;
public:
//Constructors
Matrix(int rows, int cols) : m_m(rows), m_n(cols), m_rows(std::vector<std::vector<data_type>>(rows, std::vector<data_type>(cols, 0))) {};
Matrix(std::vector<std::vector<data_type>> vect) : m_m(size(vect)), m_n(size(vect.at(0))), m_rows(std::move(vect)) {};
//Non-static methods
std::string asString() const;
//Static methods
static Matrix Identity(int dim);
static Matrix Multiply(Matrix& a, Matrix& b);
};
}
Again, with the standards I'm trying to avoid making m_rows not constant, but I'm tempted to make it mutable with the sole reason being concerns of if the matrix needs to be changed using a for loop or something of the sort.
Thanks!
As it happens I am also currently writing a Matrix class with its own iterators but from scratch. Anyway, ask yourself: Will the size of my matrix change at any point? Well, if you intend to assign to a matrix with another size, then the size will have to change. If you want to have a operator*=, that will change its size. But if you're ok with not having such functionality, const it! However, I won't in my project, for the reasons give.

Can I pass 0 to a function expecting a vector type parameter?

I have a function, as such:
void foo(int checkInt, vector<int> vect, int x) {
EXECx = x;
EXECcheckInt = checkInt;
if (EXECcheckInt > 0) {
//do something to vect
} else {
Timer.rset();
}
}
As can be seen, vect is left alone unless checkInt is above 0. So, if I want to pass checkInt 0, then it seems like I wouldn't have to worry about vect.
Therefore it would seem to me that I need some dummy value to go into this function for vect, so what value would work, or do I need to pass a dummy vector? My idea was to just pass 0, but I'm guessing that wouldn't work.
I tried to cast it, as in foo(0,(vector<int>)0,0), but I was surprised that when I tried to print out vect, it just showed up as empty (no 0 inside it), with the function written as so:
void foo(int checkInt, vector<int> vect, int x) {
for (auto i = vect.begin(); i != vect.end(); ++i)
std::cout << *i << ' ';
}
How should I go about this?
I'm working with C++98.
The code looks like the function decides whether the vector is used or not but what you want to do suggests that it is the caller who decides if the vector is used or not. Who is it really? I think you have a design problem, fix that then you dont need to cast a 0 to a vector anymore. (eg make two functions, one taking a vector, the other taking no vector as parameter)
Anyhow, you may want to look at std::optional which is only available since C++17, but it might give you some inspiration on how to handle such situation in a clean way. The "dirty" way is to pass a pointer and then check if it is a nullptr inside the function.
Your casts does not create a vector filled with 0 but a vector with size 0.
Change the function declaration to accept a reference of the vector to avoid copying memory unnecessarily like so:
void foo(int checkInt, vector<int>& vect, int x)
If you already have a vector object then you can pass that even if it is not used. If you need to construct a dummy vector then you can call the function like this:
vector<int> v;
foo (0, v, x);
You could provide an overload that can be called without the vector. You can refactor the common part into a subfunction:
void foo(int checkInt, vector<int> vect, int x) {
if (checkInt > 0) {
bar(checkInt, x);
//do something to vect
} else {
foo(checkInt, x);
}
}
void foo(int checkInt, int x) {
assert(checkInt <= 0); // maybe unnecessary. depends on what you need
bar(checkInt, x);
Timer.rset();
}
void bar(int checkInt, int x) {
EXECx = x;
EXECcheckInt = checkInt;
}
// with vect
foo(checkInt, vect, x);
// without vect
foo(0, 0);
but I was surprised that when I tried to print out vect, it just showed up as empty (no 0 inside it)
It's unclear why that surprises you. As per documentation, the constructor of vector that accepts an integer creates that many elements into the constructed vector. A vector with 0 elements is empty.
Note that you probably should reconsider whether you would want to pass the vector by value. Are you sure that you need a copy?

Sorting Array of Struct's based on String

I've been reading all the topics related to sorting arrays of structs, but haven't had any luck as of yet, so I'll just ask. I have a struct:
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
string programQuestion;
};
And I populate an array of question in main, and now have an array called questions[] so now I need to write a sort that will sort questions[] based on question.programQuestion. Based on what I've read, this is where I'm at, but I'm not sure if its even close:
int myCompare (const void *v1, const void *v2 ) {
const struct question* p1 = static_cast<const struct question*>(v1);
const struct question* p2 = static_cast<const struct question*>(v2);
if (p1->programQuestion > p2->programQuestion){
return(+1);}
else if (p1->programQuestion < p2->programQuestion){
return(-1);}
else{
return(0);}
}
If this is right I'm not sure how to call it in main. Thanks for any help!
If you're intending to use std::sort to sort this array, you likely want to declare an operator< as a method in this struct. Something like this:
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
string programQuestion;
bool operator<( const question &rhs) const;
};
bool question::operator<( const question &rhs ) const
{
return programQuestion < rhs.programQuestion;
}
The comparison function you were attempting to declare above appears to be the type qsort expects, and I would not recommend trying to qsort an array of these struct questions.
Just use std::sort. It's safer, nearly always faster (sometimes by huge margins), and generally easier to get right.
Unless there is some important reason not to do so, I would use a std::vector instead of a plain array. It is easier and safer. You could use the following code to sort your vector:
std::vector<question> questions;
// add some elements to the vector
std::sort(begin(questions), end(questions),
[](const question& q1, const question& q2) {
return q1.programQuestion < q2.programQuestion;
});
This code use some C++11 features. But you could achieve the same in previous versions of C++ by using a function object, or simply by implementing operator< in the struct (assuming you always want to sort such a struct based on that field).

How to index and assign elements in a tensor using identical call signatures?

OK, I've been googling around for too long, I'm just not sure what to call this technique, so I figured it's better to just ask here on SO. Please point me in the right direction if this has an obvious name and/or solution I've overlooked.
For the laymen: a tensor is the logical extension of the matrix, in the same way a matrix is the logical extension of the vector. A vector is a rank-1 tensor (in programming terms, a 1D array of numbers), a matrix is a rank-2 tensor (a 2D array of numbers), and a rank-N tensor is then simply an N-D array of numbers.
Now, suppose I have something like this Tensor class:
template<typename T = double> // possibly also with size parameters
class Tensor
{
private:
T *M; // Tensor data (C-array)
// alternatively, std::vector<T> *M
// or std::array<T> *M
// etc., or possibly their constant-sized versions
// using Tensor<>'s template parameters
public:
... // insert trivial fluffy stuff here
// read elements
const T & operator() (size_t a, size_t b) const {
... // error checks etc.
return M[a + rows*b];
}
// write elements
T & operator() (size_t a, size_t b) {
... // error checks etc.
return M[a + rows*b];
}
...
};
With these definitions of operator()(...), indexing/assign individual elements then has the same call signature:
Tensor<> B(5,5);
double a = B(3,4); // operator() (size_t,size_t) used to both GET elements
B(3,4) = 5.5; // and SET elements
It is fairly trivial to extend this up to arbitrary tensor rank. But what I'd like to be able to implement is a more high-level way of indexing/assigning elements:
Tensor<> B(5,5);
Tensor<> C = B( Slice(0,4,2), 2 ); // operator() (Slice(),size_t) used to GET elements
B( Slice(0,4,2), 2 ) = C; // and SET elements
// (C is another tensor of the correct dimensions)
I am aware that std::valarray (and many others for that matter) does a very similar thing already, but it's not my objective to just accomplish the behavior; my objective here is to learn how to elegantly, efficiently and safely add the following functionality to my Tensor<> class:
// Indexing/assigning with Tensor<bool>
B( B>0 ) += 1.0;
// Indexing/assigning arbitrary amount of dimensions, each dimension indexed
// with either Tensor<bool>, size_t, Tensor<size_t>, or Slice()
B( Slice(0,2,FINAL), 3, Slice(0,3,FINAL), 4 ) = C;
// double indexing/assignment operation
B(3, Slice(0,4,FINAL))(mask) = C; // [mask] == Tensor<bool>
.. etc.
Note that it's my intention to use operator[] for non-checked versions of operator(). Alternatively, I'll stick more to the std::vector<> approach of using .at() methods for checked versions of operator[]. Anyway, this is a design choice and besides the issue right now.
I've conjured up the following incomplete "solution". This method is only really manageable for vectors/matrices (rank-1 or rank-2 tensors), and has many undesirable side-effects:
// define a simple slice class
Slice ()
{
private:
size_t
start, stride, end;
public:
Slice(size_t s, size_t e) : start(s), stride(1), end(e) {}
Slice(size_t s, size_t S, size_t e) : start(s), stride(S), end(e) {}
...
};
template<typename T = double>
class Tensor
{
... // same as before
public:
// define two operators() for use with slices:
// version for retrieving data
const Tensor<T> & operator() (Slice r, size_t c) const {
// use slicing logic to construct return tensor
...
return M;
{
// version for assigning data
Sass operator() (Slice r, size_t c) {
// returns Sass object, defined below
return Sass(*this, r,c);
}
protected:
class Sass
{
friend class Tensor<T>;
private:
Tensor<T>& M;
const Slice &R;
const size_t c;
public:
Sass(Tensor<T> &M, const Slice &R, const size_t c)
: M(M)
, R(R)
, c(c)
{}
operator Tensor<T>() const { return M; }
Tensor<T> & operator= (const Tensor<T> &M2) {
// use R/c to copy contents of M2 into M using the same
// Slice-logic as in "Tensor<T>::operator()(...) const" above
...
return M;
}
};
But this just feels wrong...
For each of the indexing/assignment methods outlined above, I'd have to define a separate Tensor<T>::Sass::Sass(...) constructor, a new Tensor<T>::Sass::operator=(...), and a new Tensor<T>::operator()(...) for each and every such operation. Moreover, the Tensor<T>::Sass::operators=(...) would need to contain much of the same stuff that's already in the corresponding Tensor<T>::operator()(...), and making everything suitable for a Tensor<> of arbitrary rank makes this approach quite ugly, way too verbose and more importantly, completely unmanageable.
So, I'm under the impression there is a much more effective approach to all this.
Any suggestions?
First of all I'd like to point out some design issues:
T & operator() (size_t a, size_t b) const;
suggests you can't alter the matrix through this method, because it's const. But you are giving back a nonconst reference to a matrix element, so in fact you can alter it. This only compiles because of the raw pointer you are using. I suggest to use std::vector instead, which does the memory management for you and will give you an error because vector's const version of operator[] gives a const reference like it should.
Regarding your actual question, I am not sure what the parameters of the Slice constructor should do, nor what a Sass object is meant to be (I am no native speaker, and "Sass" gives me only one translation in the dictionary, meaning sth. like "impudence", "impertinence").
However, I suppose with a slice you want to create an object that gives access to a subset of a matrix, defined by the slice's parameters.
I would advice against using operator() for every way to access the matrix. op() with two indices to access a given element seems natural. Using a similar operator to get a whole matrix to me seems less intuitive.
Here's an idea: make a Slice class that holds a reference to a Matrix and the necessary parameters that define which part of the Matrix is represented by the Slice. That way a Slice would be something like a proxy to the Matrix subset it defines, similar to a pair of iterators which can be seen as a proxy to a subrange of the container they are pointing to. Give your Matrix a pair of slice() methods (const and nonconst) that give back a Slice/ConstSlice, referencing the Matrix you call the method on. That way, you can even put checks into the method to see if the Slice's parameters make sense for the Matrix it refers to. If it makes sense and is necessary, you can also add a conversion operator, to convert a Slice into a Matrix of its own.
Overloading operator() again and again and using the parameters as a mask, as linear indices and other stuff is more confusing than helping imo. operator() is slick if it does something natural which everybody expects from it. It only obfuscates the code if it is used everywhere. Use named methods instead.
Not an answer, just a note to follow up my comment:
Tensor<bool> T(false);
// T (whatever its rank) contains all false
auto lazy = T(Slice(0,4,2));
// if I use lazy here, it will be all false
T = true;
// now T contains all true
// if I use lazy here, it will be all true
This may be what you want, or it might be unexpected.
In general, this can work cleanly with immutable tensors, but allowing mutation gives the same class of problem as COW strings.
If you allow for your Tensor to implicitly be a double you can return only Tensors from your operator() overload.
operator double() {
return M.size() == 1 ? M[0] : std::numeric_limits<double>::quiet_NaN();
};
That should allow for
double a = B(3,4);
Tensor<> a = B(Slice(1,2,3),4);
To get the operator() to work with multiple overloads with Slice and integer is another issue. I'd probably just use Slice and create another implicit conversion so integers can be Slice's, then maybe using the variable argument elipses.
const Tensor<T> & operator() (int numOfDimensions, ...)
Although the variable argument route is kind of a kludge best to just have 8 specializations for 1-8 parameters of Slice.

Cache gauss points for numerical integration in c++

This is a question on what people think the best way to lay out my class structure for my problem. I am doing some numerical analysis and require certain "elements" to be integrated. So I have created a class called "BoundaryElement" like so
class BoundaryElement
{
/* private members */
public:
integrate(Point& pt);
};
The key function is 'integrate' which I need to evaluate for a whole variety of different points. What happens is that, depending on the point, I need to use a different number of integration points and weights, which are basically vectors of numbers. To find these, I have a class like so:
class GaussPtsWts
{
int numPts;
double* gaussPts;
double* gaussWts;
public:
GaussPtsWts(const int n);
GaussPtsWts(const GaussPtsWts& rhs);
~GaussPtsWts();
GaussPtsWts& operator=(const GaussPtsWts& rhs);
inline double gwt(const unsigned int i)
{
return gaussWts[i];
}
inline double gpt(const unsigned int i)
{
return gaussPts[i];
}
inline int numberGPs()
{
return numGPs;
}
};
Using this, I could theoretically create a GaussPtsWts instance for every call to the integrate function. But I know that I maybe using the same number of gauss points many times , and so I would like to cache this data. I'm not very confident on how this might be done - potentially a std::map which is a static member of the BoundaryElement class? If people could shed any light on this I would be very grateful. Thanks!
I had a similar issue once and used a map (as you suggested). What I would do is change the GaussPtsWts to contain the map:
typedef std::map<int, std::vector<std::pair<double, double>>> map_type;
Here I've taken your two arrays of the points and weights and put them into a single vector of pairs - which should apply if I remember my quadrature correctly. Feel free to make a small structure of the point and weight to make it more readable.
Then I'd create a single instance of the GaussPtsWts and store a reference to it in each BoundaryElement. Or perhaps a shared_ptr depending on how you like it. You'd also need to record how many points you are using.
When you ask for a weight, you might have something like this:
double gwt(const unsigned int numGPs, const unsigned int i)
{
map_type::const_iterator found = themap.find(numGPs);
if(found == themap.end())
calculatePoints(numGPs);
return themap[numGPs][i].first;
}
Alternatively you could mess around with templates with an integer parameter:
template <int N>
class GaussPtsWts...