const problems with one class referencing another

T

Torsten Wiebesiek

Hi folks,

currently I'm writing image classes for easier handling of Intel's IPP library.

My idea is to have to different classes. One class that represents a complete
image and deals with all the memeory management stuff, and another class, that
is only a tile of the image. Let's call the first MemoryImage, and the second
ReferenceImage.

My code works well for creating non const and const reference images to a non
const memory image. Unfortunately, it doesn't work for const memory images.

The following code illustrates my problem. It's neither stylistically nor
functionally perfect (in fact it's neglecting the identical byte offsets
between consecutive images lines, even though the image widths might be
different.


class MemImage {

public:

// Create image.
MemImage(int width, int height) : m_data(0) {

// check dimensions and allocate aligned memory
}

// Get width of image.
int getWidth() const { return m_width; }

// Get height of image.
int getHeight() const { return m_height; }

// Get pointer to image data.
unsigned char* getData() { return m_data; }

// Get const pointer to image data.
const unsigned char* getData() const { return m_data; }

protected:

unsigned char * m_data;
int m_width;
int m_height;

}; // class MemImage


class RefImage {

public:

RefImage(MemImage &image, int x, int y, int width, int height)
: m_data(image.getData()+y*image.getWidth()+x), m_width(width), m_height(height)
{}

// Get pointer to image data.
unsigned char* getData() { return m_data; }

// Get const pointer to image data.
const unsigned char* getData() const { return m_data; }

protected:

unsigned char *m_data;
int m_width;
int m_height;

}; // class RefImage


With the example code above, its possible to do:

void f()
{
MemImage m(400,300);
RefImage r(m, 40, 30, 200, 150);
const RefImge c(m, 40, 30, 200, 150);
}

It's also possible to change image data of m through r.getData()

The code breaks with:
void g()
{
const MemImage m(400,300);
const RefImge c(m, 40, 30, 200, 150);
}

Changing the constructor of RefImage to

RefImage(const MemImage &image, int x, int y, int width, int height)
: m_data(image.getData()+y*image.getWidth()+x), m_width(width), m_height(height)
{}

fails due to the initialization of unsigned char m_data with a const unsigned char.

Changing the member m_data of RefImage to const unsigned char, the constructor works,
but it's no longer possible to have write access to non const MemImages via a RefImage.

Can anyone break this vicious circle?

Thanks in advance,

Torsten
 
J

Jim Langston

Torsten Wiebesiek said:
Hi folks,

currently I'm writing image classes for easier handling of Intel's IPP
library.

My idea is to have to different classes. One class that represents a
complete
image and deals with all the memeory management stuff, and another class,
that
is only a tile of the image. Let's call the first MemoryImage, and the
second
ReferenceImage.

My code works well for creating non const and const reference images to a
non
const memory image. Unfortunately, it doesn't work for const memory
images.

The following code illustrates my problem. It's neither stylistically nor
functionally perfect (in fact it's neglecting the identical byte offsets
between consecutive images lines, even though the image widths might be
different.


class MemImage {

public:

// Create image.
MemImage(int width, int height) : m_data(0) {

// check dimensions and allocate aligned memory
}

// Get width of image.
int getWidth() const { return m_width; }

// Get height of image.
int getHeight() const { return m_height; }

// Get pointer to image data.
unsigned char* getData() { return m_data; }

// Get const pointer to image data.
const unsigned char* getData() const { return m_data; }

protected:

unsigned char * m_data;
int m_width;
int m_height;

}; // class MemImage


class RefImage {

public:

RefImage(MemImage &image, int x, int y, int width, int height)
: m_data(image.getData()+y*image.getWidth()+x), m_width(width),
m_height(height)
{}

// Get pointer to image data.
unsigned char* getData() { return m_data; }

// Get const pointer to image data.
const unsigned char* getData() const { return m_data; }

protected:

unsigned char *m_data;
int m_width;
int m_height;

}; // class RefImage


With the example code above, its possible to do:

void f()
{
MemImage m(400,300);
RefImage r(m, 40, 30, 200, 150);
const RefImge c(m, 40, 30, 200, 150);
}

It's also possible to change image data of m through r.getData()

The code breaks with:
void g()
{
const MemImage m(400,300);
const RefImge c(m, 40, 30, 200, 150);

I can get this to work with an extremly ugly constant cast.

const RefImage c(*(const_cast<MemImage*>( &m )), 40, 30, 200, 150);

I've been trying various things and can't figure it out. It seems that
because RefImage has an
unsigned char* and is trying to initialize it from a const unsigned char*
from unsigned char*.

The only thing I've found so far that works is making m_data public, and
initalizing with

RefImage(const MemImage &image, int x, int y, int width, int height)
: m_data(image.m_data+y*image.getWidth()+x), m_width(width),
m_height(height)
{}
 
F

Frank Birbacher

Hi!

Torsten said:
Can anyone break this vicious circle?

No. You have to create a ConstRefImage class. But you can inherit it.

struct ConstRefImage {
ConstRefImage(MemoryImage const& m, ...)
: constImage(m)
{ ... }
MemoryImage const& constImage;
... //some const member functions
};
struct RefImage : ConstRefImage {
RefImage(MemoryImage& m, ...)
: ConstRefImage(m) //cast to const
, image(m)
{ ... }
MemoryImage & image;
... //some non-const member functions
};

void foo(ConstRefImage const& image) { ... }
void bar()
{
MemoryImage m(...);
RefImage r(m, ...);
foo(r); //works
};

HTH

Some other advise: you can use std::vector instead of raw memory to
avoid memory management issues. The std::vector is required to allocate
continuous memory. So "&v[0]" will give you the pointer you need.
Getting raw memory management correct is not trivial and should be avoided.

Frank
 
T

Torsten Wiebesiek

Can anyone break this vicious circle?
No. You have to create a ConstRefImage class. But you can inherit it.

struct ConstRefImage {
ConstRefImage(MemoryImage const& m, ...)
: constImage(m)
{ ... }
MemoryImage const& constImage;
... //some const member functions
};
struct RefImage : ConstRefImage {
RefImage(MemoryImage& m, ...)
: ConstRefImage(m) //cast to const
, image(m)
{ ... }
MemoryImage & image;
... //some non-const member functions
};

void foo(ConstRefImage const& image) { ... }
void bar()
{
MemoryImage m(...);
RefImage r(m, ...);
foo(r); //works
};

Frank, that was a very good hint. Thanks! :)

I now have the following class hierarchy:

class ConstImage {...};
class Image : public virtual ConstImage {...};

class MemImage : public Image {...};

class ConstRefImage : public virtual ConstImage {...};
class RefImage : public ConstRefImage, public Image {...};

Virtual inheritance, because ConstImage is not abstract but
deals with height and width information. Seems to work.

Some other advise: you can use std::vector instead of raw memory to
avoid memory management issues. The std::vector is required to allocate
continuous memory. So "&v[0]" will give you the pointer you need.
Getting raw memory management correct is not trivial and should be avoided.

I'd love to, but I'm not sure, whether it's really allocating properly
alligned memory. Therefore, I use Intels IPP Memory allocation function:

Ipp<datatype>* ippiMalloc_<mod>(int width, int height, int* pStepBytes);

It's neither very nice nor very convenient, but, well, it's a speed optimized
C library. There are some design drawback, but at least it's very fast.


Regards,

Torsten
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top