Home > Mobile >  Set the bounds of an array after object initialisation in cpp
Set the bounds of an array after object initialisation in cpp

Time:05-19

I'm working on an image renderer in C that I wrote from scratch (I don't want to use anything but standard libraries), but I'm having some trouble when trying to store the image. The class I use to store images looks like this:

class RawImage
{
    private:
        RGB pixels[][][3] = {};
    public:
        int width = 0;
        int height = 0;
        RawImage(int width, int height)
        {
            this->width = width;
            this->height = height;
        };
        RGB GetPixel(int x, int y)
        {
            if (x < 0 || x > width - 1)
                return RGB(0.f, 0.f, 0.f);
            if (y < 0 || y > height - 1)
                return RGB(0.f, 0.f, 0.f);
            return pixels[x][y];
        };
        int SetPixel(int x, int y, RGB color)
        {
            if (x < 0 || x > width - 1)
                return -1;
            if (y < 0 || y > height - 1)
                return -1;
            this->pixels[x][y] = color;
            return 0;
        }
};

When I try to compile this code, the g compiler gives the following error:

declaration of ‘pixels’ as multidimensional array must have bounds for all dimensions except the first.

How do I use a multidimensional array of which the 2 first dimensions vary in size, but the third dimension is of a fixed size?

CodePudding user response:

Assuming (as you have confirmed in the comments) that your RGB type is a class or structure with three components, with a constructor of the form used in your GetPixel function, then you actually want a 2D array. However (as also mentioned in the comments), it is generally more efficient to store bitmaps as flattened, one-dimensional arrays of size width × height. The appropriate element in that array can then be indexed using the formula array[y * width x] (assuming a row-major order and y-ordinates that increase down the bitmap).

You still have the issue of a dimension that is not known at compile time, so you can't use a normal array. But the std::vector container is ideal for this: just resize it in your RawImage constructor, and it can then be used in much the same way as a plain array. Also, the memory used will be automatically freed when an object of the RawImage class is destroyed.

Here is a possible implementation of your class using such a std::vector:

#include <vector>

class RawImage {
private:
    std::vector<RGB> pixels;
public:
    int width = 0;
    int height = 0;
    RawImage(int width, int height)
    {
        this->width = width;
        this->height = height;
        pixels.resize(width * height);
    };
    RGB GetPixel(int x, int y)
    {
        if (x < 0 || x >= width )
            return RGB(0.f, 0.f, 0.f);
        if (y < 0 || y >= height)
            return RGB(0.f, 0.f, 0.f);
        return pixels[y * width   x];
    };
    int SetPixel(int x, int y, RGB color)
    {
        if (x < 0 || x >= width)
            return -1;
        if (y < 0 || y >= height)
            return -1;
        pixels[y * width   x] = color;
        return 0;
    }
};

Important Note: In order to use the std::vector<RGB> container like this, the RGB class/structure must have a default constructor. I don't know exactly how you have implemented that class, but something like the following would work:

struct RGB {
    float r, g, b;
    RGB(float fr, float fg, float fb) : r{ fr }, g{ fg }, b{ fb } { }
    RGB() : r{ 0 }, g{ 0 }, b{ 0 } { } // Default c'tor required by std::vector
};

Or, for brevity, you could 'merge' your default constructor into the one that takes three float arguments by providing default vales for each of those arguments:

struct RGB {
    float r, g, b;
    RGB(float fr = 0, float fg = 0, float fb = 0) : r{ fr }, g{ fg }, b{ fb } { }
};

CodePudding user response:

Set the bounds of an array after object initialisation in cpp

The size of an array never changes through its lifetime. It's set upon creation. Technically this isn't a problem for you because you can initialise the array in the constructor.

But, size of an array variable must be compile time constant, so you cannot accept the size as a constructor parameter.

You can use a dynamic array. Most convenient way is to use std::vector.

CodePudding user response:

Arrays are not really first size citizens in C language, and multi-dimensional arrays are not at all. There is no way to declare a multi-dimensional array where more than first dimension is not a compile time constant, full stop. The rationale is that plain arrays are low level objects and are intended to only be used in higher level containers. Unfortunately, building true multi-level containers wrapping a multidimensional array whose dimension are only known at compile time is far from trivial because of the way iterators work. A simple way if you can accept it, is to use operator () as an accessor method: pixels(x, y) instead of pixels[x][y] in a container aware of the dynamic dimensions.

  • Related