Multidimensional array member initialization

  • Thread starter olivier.scalbert
  • Start date
O

olivier.scalbert

Hello,

I would like to create an Image class. A use of this class could be
something as:

Image image1(1000, 1000);
Image image2(2000, 1000);

Color3d color;

image1.fill(color);
image2.fill(color);

Here is the code of the class:

struct Color3d
{
double r,g,b;
}

class Image
{
public:
Image(int width, int height);
~Image();

void fill(Color3d color);

private:
int _width;
int _height;

Color3d _pixels[][]; // Does not work !
};

Image::Image(int width, int height) : _width(width), _height(height)
{
_pixels = new Color3d[width][height]; // Does not work !
}

Image::~Image()
{
delete [][] _pixels; // Does not work
}

void Image::fill(Color3d color)
{
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
_pixels[x][y] = color;
}
}
}

As you can imagine, I have some problems around the pixels definition.

I see two alternatives:
- using templates;
- allocate a single dimension array of pixels and manage the
coordinates conversion myself.

I am sure there are some more elegant solutions, but I have no ideas.

Thanks to help me,

Olivier
 
F

Fred Zwarts

Hello,

I would like to create an Image class. A use of this class could be
something as:

Image image1(1000, 1000);
Image image2(2000, 1000);

Color3d color;

image1.fill(color);
image2.fill(color);

Here is the code of the class:

struct Color3d
{
double r,g,b;
}

class Image
{
public:
Image(int width, int height);
~Image();

void fill(Color3d color);

private:
int _width;
int _height;

Color3d _pixels[][]; // Does not work !
};

Image::Image(int width, int height) : _width(width), _height(height)
{
_pixels = new Color3d[width][height]; // Does not work !
}

Image::~Image()
{
delete [][] _pixels; // Does not work
}

void Image::fill(Color3d color)
{
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
_pixels[x][y] = color;
}
}
}

As you can imagine, I have some problems around the pixels definition.

I see two alternatives:
- using templates;
- allocate a single dimension array of pixels and manage the
coordinates conversion myself.

I am sure there are some more elegant solutions, but I have no ideas.

The size of a class is fixed. You can't use arrays with undefined size in a class.
With one-dimensional arrays you will have the same problem.
Use std::vector, which can be used as an array, but the size of which can be adjusted
in the constructor of your class.
 
G

Gert-Jan de Vos

Hello,

I would like to create an Image class. A use of this class could be
something as:

    Image image1(1000, 1000);
    Image image2(2000, 1000);

    Color3d color;

    image1.fill(color);
    image2.fill(color);

Here is the code of the class:

struct Color3d
{
    double r,g,b;

}

class Image
{
public:
    Image(int width, int height);
    ~Image();

    void fill(Color3d color);

private:
    int _width;
    int _height;

    Color3d _pixels[][]; // Does not work !

};

As you can imagine, I have some problems around the pixels definition.

I see two alternatives:
- using templates;
- allocate a single dimension array of pixels and manage the
coordinates conversion myself.

I am sure there are some more elegant solutions, but I have no ideas.

Use a vector<Color3d> for your pixels. Index as (width*y + x). You can
use operator[] that returns a proxy class that represents the left
most index. The proxy class then implements another operator[] to
support image[y][x] style pixel access.

You may want to make your Image class a template class to support
different pixel types.
 
G

Gert-Jan de Vos

Hello,

I would like to create an Image class. A use of this class could be
something as:

    Image image1(1000, 1000);
    Image image2(2000, 1000);

    Color3d color;

    image1.fill(color);
    image2.fill(color);

Here is the code of the class:

struct Color3d
{
    double r,g,b;

}

class Image
{
public:
    Image(int width, int height);
    ~Image();

    void fill(Color3d color);

private:
    int _width;
    int _height;

    Color3d _pixels[][]; // Does not work !

};

Image::Image(int width, int height) : _width(width), _height(height)
{
    _pixels = new Color3d[width][height]; // Does not work !

}

Image::~Image()
{
    delete [][] _pixels; // Does not work

}

void Image::fill(Color3d color)
{
    for (int y = 0; y < _height; y++)
    {
        for (int x = 0; x < _width; x++)
        {
            _pixels[x][y] = color;
        }
    }

}

As you can imagine, I have some problems around the pixels definition.

I see two alternatives:
- using templates;
- allocate a single dimension array of pixels and manage the
coordinates conversion myself.

I am sure there are some more elegant solutions, but I have no ideas.

No need to handle memory management yourself. vector is very good at
it.
Consider making the functions on Image free functions. That way, you
can
add functions later without changing the basic Image type.

Here's an example of how to use vector in combination with proxy
objects
to support array style [][] indexing.

Hope this helps.

Gert-Jan

#include <vector>

template <typename T>
class Image
{
class Indexer
{
public:
Indexer(T* data) : data_(data)
{
}

T& operator[](int x) const
{
return data_[x];
}

private:
T* data_;
};

class ConstIndexer
{
public:
ConstIndexer(const T* data) : data_(data)
{
}

T operator[](int x) const
{
return data_[x];
}

private:
const T* data_;
};

public:
Image(int width, int height) :
width(width),
height(height),
data(width*height)
{
}

int width() const
{
return width_;
}

int height() const
{
return height_;
}

Indexer operator[](int y)
{
return Indexer(&data_[y*width_]);
}

ConstIndexer operator[](int y) const
{
return ConstIndexer(&data_[y*width_]);
}

private:
int width_;
int height_;
std::vector<T> data_;
};

struct Color3d
{
double r, g, b;
};

void fill(Image<Color3d>& img, Color3d color)
{
for (int y = 0; y < img.height(); ++y)
for (int x = 0; x < img.width(); ++x)
img[y][x] = color;
}
 
O

olivier.scalbert

No need to handle memory management yourself. vector is very good at
it.
Consider making the functions on Image free functions. That way, you
can
add functions later without changing the basic Image type.

Here's an example of how to use vector in combination with proxy
objects
to support array style [][] indexing.

Hope this helps.

Gert-Jan

#include <vector>

template <typename T>
class Image
{
    class Indexer
    {
    public:
        Indexer(T* data) : data_(data)
        {
        }

        T& operator[](int x) const
        {
            return data_[x];
        }

    private:
        T* data_;
    };

    class ConstIndexer
    {
    public:
        ConstIndexer(const T* data) : data_(data)
        {
        }

        T operator[](int x) const
        {
            return data_[x];
        }

    private:
        const T* data_;
    };

public:
    Image(int width, int height) :
        width(width),
        height(height),
        data(width*height)
    {
    }

    int width() const
    {
        return width_;
    }

    int height() const
    {
        return height_;
    }

    Indexer operator[](int y)
    {
        return Indexer(&data_[y*width_]);
    }

    ConstIndexer operator[](int y) const
    {
        return ConstIndexer(&data_[y*width_]);
    }

private:
    int width_;
    int height_;
    std::vector<T> data_;

};

struct Color3d
{
    double r, g, b;

};

void fill(Image<Color3d>& img, Color3d color)
{
    for (int y = 0; y < img.height(); ++y)
        for (int x = 0; x < img.width(); ++x)
            img[y][x] = color;

}

Thanks. Your solution is very elegant and also very efficient.

Olivier
 
G

Gert-Jan de Vos

----------
"Gert-Jan de Vos" <[email protected]> ha scritto nel messaggio
Hope this helps.

Gert-Jan

#include <vector>
etc
---------

i have copy above code adding only some macro,
add 3 "_" in the constructor Image(int, int),
and the main() function for debug.

not understand why img.width()
is called each cicle of the inner loop; why not use
just x<img.width_?

width_ and height_ are private functions such that
these values can only be set when constructing an
Image. When these values where public, the values
could be changed, and the data content would be
meaningless or even invalid. In case you are worried
about possible function call overhead: width()/
height() are inline functions and all sensible
compilers will generate exactly the same code as
with the public members.
yes i not have understood all but seems to me there
is something wrong g[768][1024].b
not seg fault, so for me could be something wrong.

Your image was created as 768x1024 in size. Therefore
your index is out of range. This is translated into a
vector out of range index. This results in good C and
C++ tradition in Undefined Behavior: anything can
happen, including seg fault.
than for me the centre of the exercise is:
immage has to be one big array without holes in it.
Can some of you could say "vector" operate in one big array
without holes in it?

Sorry, I do not understand your question.
 
G

Gert-Jan de Vos

#"could be changed" from who? the programmer
#that i hope know what he is doing: all must be public

Making member data private is a well established OO principle.
This protects an object from unintended state changes. The
object itself takes care of being in a consistent state
always.
#it seems cpp library vector has no hole in its data representation

C++03 specifies that vector stores its elements in a single
contiguous block of memory. My Image implementation indeed makes
use of this property of vector. The same will not work with deque
or list.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top