1

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).

7
  • 1
    If it's a true matrix it would be more efficient to create a 1d vector and use the index calculation (x + y * width) to find the element. You can wrap this in a class for convenience. Commented Mar 19, 2015 at 15:49
  • We need a little more code to help you here. Can you show us where you create the BlurFilter and how the matrix is passed to Matrix's constructor? Commented Mar 19, 2015 at 15:51
  • 1
    Actually the standard doesn't use "vague" language. Cryptic, maybe. Confusing, certainly to some. Abstract, hell yes. but vague no. It's the verbose english that is vague and open to interpretation. Commented Mar 19, 2015 at 15:53
  • 1
    Works fine at ideone.com/7VXnQk. Commented Mar 19, 2015 at 15:59
  • Have you tried a very basic repo? I just did one and it worked OK. It was just a class accepting a vector of vectors in the constructor, assigning it to a private member, and main creating an instance, passing in an initialised (as you have) vector of vectors. Commented Mar 19, 2015 at 16:00

2 Answers 2

2

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

This is cool! I have two questions. Can I access Matrix elements using convolutionMatrix[row][col]? And can I create a std::unordered_map< std::string , Matrix > to store or point to a bunch of these things ? Thanks!.
I don't think it works for a one dimensional array, does it? I get an error.
How do I create a Matrix of a certain dimensions without providing an initialiser list?
@SimonWoodward, you can use BlurFilter::BlurFilter() : convolutionMatrix(M, std::vector<double>(N)) { } for that.
1

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...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.