DomainFlag
DomainFlag

Reputation: 564

How to define a variable in heap memory in a struct with C++?

I have 2 Structures, Color one:

struct Color
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
};

And the Image structure:

struct matrixImage
{
    Image Img;
    struct Color T[MAX][MAX];
    int Width;
    int Height;
};

In T table, I am storing the pixels of an image. But the maximum size of the array is to low(on stack), so I can't store every pixel of the image. I know how to define an array in Heap like this

-> struct Color *newTable = new struct Color[anyNumber];

But how can I write this in struct matrixImage, any help?

Upvotes: 2

Views: 1088

Answers (3)

Xirema
Xirema

Reputation: 20396

I'd do something like this:

//Switched to a class because we need some encapsulation or this will be bug-prone.
class matrixImage
{
    //Do you need this? What kind of object is "Image"?
    //Image Img;
    std::vector<Color> pixel_data;
    int Width;
    int Height;
public:
    matrixImage(int width = 1, int height = 1) :
    Width(width), Height(height), pixel_data(width * height) 
    {
    }

    //You can add bounds-checking if you need it, i.e. make sure y is less than Height, 
    //make sure x is less than Width. Not every application needs it, and you need a 
    //clear semantic of "what should happen" if you specify an invalid index.
    Color & get_color(int x, int y) {
        return pixel_data[y * Width + x];
    }
    //We have two versions to handle the case where your object is made "const"
    Color const& get_color(int x, int y) const{
        return pixel_data[y * Width + x];
    }

    //Hey, we can use the function we just defined above this one!
    void set_color(int x, int y, Color c) {
        get_color(x, y) = c;
    }

    //This only resizes the canvas. Doing proper "Resizing" is beyond the scope of what 
    //we're discussing here.
    void set_size(int new_width, int new_height) {
        std::vector<Color> new_data(new_width * new_height);

        //This case is pretty easy
        if(new_width == Width) {
            std::copy(
                pixel_data.begin(), 
                pixel_data.begin() + std::min(pixel_data.size(), new_data.size()), 
                new_data.begin()
            );
        //This gets complicated
        } else if(new_width < Width) {
            for(size_t y = 0; y < std::min(Height, new_height); y++) {
                std::copy(
                    pixel_data.begin() + y * Width,
                    pixel_data.begin() + y * Width + new_width,
                    new_data.begin() + y * new_width
                );
            }
        //Similar logic, but slightly different.
        } else {
            for(size_t y = 0; y < std::min(Height, new_height); y++) {
                std::copy(
                    pixel_data.begin() + y * Width,
                    pixel_data.begin() + (y + 1) * Width,
                    new_data.begin() + y * new_width
                );
            }
        }
        pixel_data = new_data;
        Width = new_width;
        Height = new_height;
    }

    //I leave this last one as an exercise to the reader, as it's beyond my expertise.
    void resize(int new_width, int new_height);
};

This will handle dynamic memory allocation for you (and of course, deallocation) and give you some basic functionality to work directly with the underlying data if you absolutely need to.

Upvotes: 4

Jonathan Wakely
Jonathan Wakely

Reputation: 171313

#include <memory>

struct matrixImage
{
    Image Img;
    int Width;
    int Height;
    std::unique_ptr<Color[]> colors;
    Color& color(int x, int y);
};

Color& matrixImage::color(int x, int y)
{
    if (x >= Width || y >= Height)
        throw std::out_of_range("bad co-ordinates");
    return colors[y*Width + x];
}

// ...

matrixImage mimg;
mimg.Width = 20;
mimg.Height = 100;
mimg.colors = std::make_unique<Color>(mimg.Width*mimg.Height);

It would be better to encapsulate the allocation inside a constructor, that takes the width and height as arguments:

matrixImage::matrixImage(Image img, int width, int height)
: Img(img), Width(width), Height(height), colors(std::make_unique<Color>(mimg.Width*mimg.Height))
{ }

Upvotes: 0

Zan Lynx
Zan Lynx

Reputation: 54325

You have the answer to your own question, which is to use a pointer in the struct. Then you would use new to get heap memory and store the result in your pointer.

But no, don't do this manually. Learn how to write "Modern C++" (look it up) which almost never uses new or delete, and for good reasons.

Use std::vector here. Really.

Ideally you would wrap this entire thing into some kind of Bitmap class which hides the vector and provides member functions to access pixels. Not virtual functions, because efficiency is very important for graphics.

Upvotes: 3

Related Questions