Initialize std::vector in class's initializer list - c++

I'm not sure if I should ask this at StackOverflow or at CodeReview. But because I couldn't find a similair problem, I'm posting it here.
ATM I'm optimizing the code of a simple image manipulation application.
One of the targets is to give all the convolution effect classes their respective matrix as their private variable. Because const-correctness this wasn't done earlier, but the quickfix to solve the introduced problems with const-correctness wasn't sparely with memory and cpu-cycles.
So I decided to init the convolutionMatrix at class-initializiation-level with a std::vector<std::vector<double>> since creating dozens of constructors to make each initialisation with std::array<std::array<double>,\d+>,\d+> possible, is inefficient.
BlurFilter::BlurFilter() : ColorEffect(), convolutionMatrix(
std::vector<std::vector<double>>{
std::vector<double>{ 0.0, 0.0, 1.0, 0.0, 0.0 },
std::vector<double>{ 0.0, 1.0, 1.0, 1.0, 0.0 },
std::vector<double>{ 1.0, 1.0, 1.0, 1.0, 1.0 },
std::vector<double>{ 0.0, 1.0, 1.0, 1.0, 0.0 },
std::vector<double>{ 0.0, 0.0, 1.0, 0.0, 0.0 }
} )
{
}
However. the application breaks at runtime in the Matrix constructor with an std::out_of_range-exception with the what()-message:
what(): vector::_M_range_check: __n (which is 0) >= this->size() (which is 0)"
Aka multidimensionalVector.size() is somehow 0.
Matrix::Matrix( const std::vector<std::vector<double>>& multidimensionalVector )
{
this->xLength = multidimensionalVector.size();
this->yLength = ( *multidimensionalVector.begin() ).size();
this->values = multidimensionalVector;
}
Honestly I don't understand why the size of the multidimentsionalVector is zero at that moment at all since I'm passing an initialized vector of vectors which could be -as shown- copy-constructed (or move-constructed) over to the values-variable of the Matrix class. Changing multidimensionalVector copy-by-value don't make the difference.
Could someone explain where and/or what is going wrong here?
(PS: I'd prefer answers written in own words (aka in Plain English) instead of citing directly from the C++ standard documents because of the used vague and confusing academic/scientific language).

FWIW, you can simplify your code quite a bit. Here's an example that works:
#include <iostream>
#include <vector>
struct Matrix
{
Matrix(const std::vector<std::vector<double>>& multidimensionalVector);
size_t xLength;
size_t yLength;
std::vector<std::vector<double>> values;
};
Matrix::Matrix( const std::vector<std::vector<double>>& multidimensionalVector ) : xLength(0), yLength(0), values(multidimensionalVector)
{
this->xLength = values.size();
std::cout << "xLength: " << xLength << std::endl;
if ( xLength > 0 )
{
this->yLength = ( *values.begin() ).size();;
}
std::cout << "yLength: " << yLength << std::endl;
}
struct BlurFilter
{
BlurFilter();
Matrix convolutionMatrix;
};
BlurFilter::BlurFilter() : convolutionMatrix( { { 0.0, 0.0, 1.0, 0.0, 0.0 },
{ 0.0, 1.0, 1.0, 1.0, 0.0 },
{ 1.0, 1.0, 1.0, 1.0, 1.0 },
{ 0.0, 1.0, 1.0, 1.0, 0.0 },
{ 0.0, 0.0, 1.0, 0.0, 0.0 } } )
{
}
int main()
{
BlurFilter f;
}

Well, This is embarrassing of me.
It seems I've fixed my own problem unintentionally when I was stripping and optimizing my code for posting this question. I didn't thought about to try out the streamlined code before posting it.
Putting
this->values = multidimensionalVector;
did the job.
The original of the Matrix-constructor which seemed to raise the std::out_of_range-exception was this:
Matrix::Matrix( const std::vector<std::vector<double>>& multidimensionalVector )
{
this->xLength = multidimensionalVector.size();
this->yLength = ( *multidimensionalVector.begin() ).size();
for( int x = 0; x < this->xLength; x++ )
{
for( int y = 0; y < this->yLength; y++ )
{
this->set( x, y, multidimensionalVector.at( x ).at( y ) );
}
}
}
Within Matrix::set(int x, int y, double newValue ), the x and y parameters are always checked if they're in between -1 and this->xLength && between -1 and this->yLength.
But the x and y parameters are never checked if they're in bounds with the (then not initialized) this->values...

Related

Can I compute values that require a special function during compilation of C++?

I appreciate I am being somewhat vague about what is exactly my issue, but I think that the fundamental question is clear. Please bear with me for a moment.
In brief, I have a static constexpr array of points which are used to find certain bounds I need to use. These bounds depend only on the array, so they can be precomputed. However, we want to be able to change these points and it is a pain to go and change every value every time we try to test something.
For example, let's say that I have the following setup:
The static constexpr array is
static constexpr double CHECK_POINTS[7] = { -1.5, -1.0, -0.5, 0.0, -0.5, 1.0, 1.5 };
and then in a function I'm calling, I have the following block of code:
std::vector<double> bounds = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
for(int i=0; i<bounds.size(); i++)
{
bounds[i] = std::exp(CHECK_POINTS[i]);
}
Clearly, the values of bounds can be computed during compilation. Is there anyway I can make gcc do that?
EDIT: The vector in my code block is not essential, an array will do.
constexpt std::vector does not work here, but you can use std::array.
std::exp is not constexpr
so you need to find constexpr alternatives
it would work in gcc as an extension.
static constexpr double CHECK_POINTS[7] = { -1.5, -1.0, -0.5, 0.0, -0.5, 1.0, 1.5 };
static constexpr auto vec = [](){
std::array bounds = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
for(int i=0; i<bounds.size(); i++)
{
bounds[i] = std::exp(CHECK_POINTS[i]);
}
return bounds;
}();
it's would compile fine with gcc https://godbolt.org/z/x5a9q9M1d
(constexpr std::exp is an gcc extension, thanks to #phuclv to point out)

Send a matrix as a proc argument in Chapel

I'm getting an error when I try to send a matrix into a proc. I'm pretty sure I'm doing something very wrong, can't figure it out.
use LinearAlgebra;
proc main() {
var A = Matrix(
[0.0, 0.8, 1.1, 0.0, 2.0]
,[0.8, 0.0, 1.3, 1.0, 0.0]
,[1.1, 1.3, 0.0, 0.5, 1.7]
,[0.0, 1.0, 0.5, 0.0, 1.5]
,[2.0, 0.0, 1.7, 1.5, 0.0]
);
check_dims(A);
}
proc check_dims(A: Matrix) {
var t: bool = false;
if (A.domain.dim(1) == A.domain.dim(2)){
t = true;
}
return t;
}
Gives me
mad.chpl:3: In function 'main':
mad.chpl:14: error: unresolved call 'check_dims([domain(2,int(64),false)] real(64))'
mad.chpl:17: note: candidates are: check_dims(A: Matrix)
I'm using chpl Version 1.15.0
Linear algebra objects (like matrices and vectors) are represented as arrays in Chapel. Therefore, changing Matrix (a type that does not exist) to [] (the syntax for array-type) should work as expected:
use LinearAlgebra;
proc main() {
var A = Matrix(
[0.0, 0.8, 1.1, 0.0, 2.0]
,[0.8, 0.0, 1.3, 1.0, 0.0]
,[1.1, 1.3, 0.0, 0.5, 1.7]
,[0.0, 1.0, 0.5, 0.0, 1.5]
,[2.0, 0.0, 1.7, 1.5, 0.0]
);
check_dims(A);
}
proc check_dims(A: []) {
var t: bool = false;
// method is dim()
if (A.domain.dim(1) == A.domain.dim(2)){
t = true;
}
return t;
}

Find index range of specific values in sorted vector of vectors

I have a sorted std::vector<std::vector<double>> of x,y,z values as shown below,
0.0, 0.0, 0.0
0.0, 0.0, 0.1
0.0, 0.0, 0.2
0.0, 0.1, 0.0
0.0, 0.2, 0.1
0.0, 0.2, 0.3
I want to find all z values of a specific x and y value,
ex - z values of 0.0, 0.0, should return
0.0, 0.0, 0.0
0.0, 0.0, 0.1
0.0, 0.0, 0.2
I tried using
struct MatchDouble
{
MatchDouble(double _x,double _y) : x(_x), y(_y) {}
bool operator()(std::vector<double> &n)
{
return fabs(x - n[0]) < FLT_EPSILON && fabs(y - n[1]) < FLT_EPSILON;
}
private:
double x, y ;
};
it = find_if(allpoints.begin(), allpoints.end(),MatchDouble(0.0,0.0));
But this only gives me the iterator to a single vector value. What method is best suited to achieve this?
Thank you.
std::vector<std::vector<double>> ret;
std::copy_if(allpoints.begin(), allpoints.end(), std::back_inserter(ret), MatchDouble(0.0,0.0));
return ret;
This creates a new vector ret of the same type as allpoints and copy only the points of interest using copy_if

Multiplying Transform and Matrix types in Eigen

To me this should just work, so the fact it does not, almost certainly means I am the one in the wrong. Even though in principle a Transform< double, 3, Affine > is the same as a Matrix< double, 4, 4 >, they cannot be used together sensibly:
Affine3d rotMat( AngleAxisd( 45.0, ( Vector3d() << 0.0, 1.0, 0.0 ).finished() ) );
Matrix4d m;
m << 1.0, 0.0, 0.0, 6.0,
0.0, 1.0, 0.0, 6.0,
0.0, 0.0, 1.0, 6.0,
0.0, 0.0, 0.0, 1.0;
m = m * rotMat;
Results in a 'no match for operator=' error on the last line, and the in-place multiplication operator results in the same, trying to initialise a Matrix4d with Affine3d does not work either. Does anybody know how to actually use the Transform class in any useful way?
Thanks,
Cam
Just write:
m = m * rotMat.matrix();
I don't know if it is an oversight that Eigen doesn't define this multiplication implicitly or if it might interfere with other use cases of the library.

3d array c/c++ initialization/conversion

float sampleGrid1[5][5][5] =
{
{
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0}
},
{
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0}
},
{
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 1.0, 1.0, 1.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0}
},
{
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0}
},
{
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0}
}
};
typedef struct
{
int Nx;
int Ny;
int Nz;
float*** M;
}OG;
Relevant function:
OG *newOG(){
OG *newOG = (OG *)malloc(sizeof(OG));
if (newOG == NULL)
{
throw std::exception("newOG : no memory is available");
}
return newOG;
}
int initiateOG(OG *MyOG)
{
ifstream dump("OGdump3.txt");
if (dump.is_open())
{
while ( dump.good() )
{
dump >> MyOG->Nx;
dump >> MyOG->Ny;
dump >> MyOG->Nz;
MyOG->M = new float**[MyOG->Nx];
for(int i = 0; i < MyOG->Nx; i++)
{
MyOG->M[i] = new float*[MyOG->Ny];
for(int j = 0; j < MyOG->Ny; j++)
{
MyOG->M[i][j] = new float[MyOG->Nz];
}
}
for(int z=0;z < MyOG->Nz; z++){
for(int y=0;y < MyOG->Ny; y++){
for(int x=0;x < MyOG->Nx; x++){
dump >> MyOG->M[x][y][z];
}
}
}
}
dump.close();
}
else return 0;
return 1;
}
I want to hard code some sample grids into the code, but don't know the best way to create them, do i have to use for loops?
i don't want to change my typedef struct OG, if possible
Modified:
OG *occupancyGrid;
void initialize3dArray(int x, int y, int z,float*** array)
{
array = new float**[x];
for(int i = 0; i < x; i++)
{
array[i] = new float*[y];
for(int j = 0; j < y; j++)
{
array[i][j] = new float[z];
}
}
}
void sampleOG1()
{
occupancyGrid = newOG();
occupancyGrid->Nx = 5;
occupancyGrid->Ny = 5;
occupancyGrid->Nz = 5;
initialize3dArray(5, 5, 5,occupancyGrid->M);
for(int z=0;z < occupancyGrid->Nz; z++){
for(int y=0;y < occupancyGrid->Ny; y++){
for(int x=0;x < occupancyGrid->Nx; x++){
occupancyGrid->M[x][y][z] = sampleGrid1[x][y][z];
}
}
}
}
initialize3dArray this function doesn't have compiling error, but still causing the program to crash
Yes. that will not compile, because float[5][5][5] and float *** aren't same type. They're not even compatible type. One cannot convert to other automatically.
However, float[5][5][5] can convert to float (*)[5][5] automatically. So this is legal code:
float (*m)[5][5];
m = sampleGrid1; //legal - allowed!
Demo : http://ideone.com/RwAwI
So define OG as,
struct OG
{
int Nx;
int Ny;
int Nz;
float (*M)[5][5];
};
If you OG as defined above, then you can write this:
OG* temp = newOG();
temp->Nx = 5;
temp->Ny = 5;
temp->Nz = 5;
occupancyGrid->M = sampleGrid1; //DONT use &
Isn't the error clear? float[5][5][5] is not as related to float*** as you think it is.
Use a std::vector<std::vector<std::vector<float> > > instead and avoid the whole mess.
float x[2][2] is a 2D array of float - it's not an 1D array of pointers to float. The conversion from array to pointer only works for the first dimension of such arrays.
Given float x[2][2] you reserve space for 4 floats. A float ** variable on the other hand is a pointer to a pointer to a float - there's no pointers anywhere in float x[2][2]
The same of course holds true for a 3D array - your 3D array has no sneakily hidden pointers inside it, it cannot be treated as a float ***