const design problem

F

Frank Neuhaus

Hi,

I am writing some template class to hold images. The template parameter is
simply the type of the pixels. I want the same class to also be able to
refer to sub-images of other Images (without refcounting or anything like
that - i.e. using the subimage is only allowed while the original image is
still alive).

While my copy constructor performs a deep-copy of the image, I added the
following constructor for sub-images:

Image(Image<T>& img, int left, int top, int width, int height);

Now say I have an image 'im' I can for example create another image that
refers to this image as follows:

Image<unsigned char> subim(im,10,10,50,50);

The problem is the following:

Assume 'im' is a const Image<unsigned char>. My constructor can no longer be
called since it doesn't accept a const Image. However I can not add the
const either, because someone could then modify the resulting subimage. So
what is actually needed is something that only allows the constructor to be
called for const Images, if the first parameter is a const Image... i.e

const Image<unsigned char> subim(im,10,10,50,50); // Ok
Image<unsigned char> subim(im,10,10,50,50); // Error, 'subim' not const

AFAIK, there is no way to achieve the above. Or is there?

My Ideas on the problem so far:

a)

Say I wrote a member function that returned the subimage as a const
Image<unsigned char>.

Can I assume that

const Image<unsigned char> subim=im.getSubimage(10,10,50,50);

_never_ calls the copy-constructor or the = operator of the Image (remember
that would trigger an expensive deep copy due to my copy-constructor and
=operator implementation) ?

It will _definitely_ call the copy-constructor though, if subim is not const
right?

b)

What I am currently doing to achieve the desired behavior is a bit of
template trickery:

I added two typedefs:

template<typename T>
class Image
{
public:
typedef typename boost::add_const<T>::type const_pixeltype;
typedef typename boost::remove_const<T>::type nonconst_pixeltype;
[...]
};

const_pixeltype represents T with const, so if T="unsigned
char"->const_pixeltype="const unsigned char"
nonconst_pixeltype represents T without const, so if T="const unsigned
char"->nonconst_pixeltype="unsigned char"

Now I overloaded the existing constructor with this:

Image(const Image<nonconst_pixeltype>& img, int left, int top, int width,
int height);

internally, this constructor makes sure (using a boost static assertion)
that you can only call it when T==const_pixeltype:

So

Image<const unsigned char> subim(im,10,10,50,50); // ok

but

Image<unsigned char> subim(im,10,10,50,50); // boost static assert!

Now since Image<const unsigned char> should be semantically equivalent, I
created an 'evil' :) conversion:

operator const Image<nonconst_pixeltype>&() const
{
return *(const Image<nonconst_pixeltype>*)this;
}

This allows an Image<const unsigned char> to be used as a const
Image<unsigned char>.

Though it works, I consider this solution as not very 'clean'. It is also a
bit confusing to use for people.
What do you think of this solution? Is there any nice(r) way to achieve what
I want? Or is it probably better to say - sorry - no support for subimages
of const images?

Thanks alot
Frank
 
A

Alf P. Steinbach

* Frank Neuhaus:
I am writing some template class to hold images. The template parameter
is simply the type of the pixels. I want the same class to also be able
to refer to sub-images of other Images (without refcounting or anything
like that - i.e. using the subimage is only allowed while the original
image is still alive).

While my copy constructor performs a deep-copy of the image, I added the
following constructor for sub-images:

Image(Image<T>& img, int left, int top, int width, int height);

Now say I have an image 'im' I can for example create another image that
refers to this image as follows:

Image<unsigned char> subim(im,10,10,50,50);

The problem is the following:

Assume 'im' is a const Image<unsigned char>. My constructor can no
longer be called since it doesn't accept a const Image. However I can
not add the const either, because someone could then modify the
resulting subimage. So what is actually needed is something that only
allows the constructor to be called for const Images, if the first
parameter is a const Image... i.e

const Image<unsigned char> subim(im,10,10,50,50); // Ok
Image<unsigned char> subim(im,10,10,50,50); // Error, 'subim' not const

AFAIK, there is no way to achieve the above. Or is there?

You can provide both constructors.

The problem with that is that a constructor doesn't innately know whether it's
constructing an instance that will be 'const' after construction, and
furthermore it doesn't know that an image passed by reference to const is
originally const (no aliasing). So in spite of having achieved the technical
goal of channeling the const argument to specific constructor code, essentially
nothing is achieved with respect to the design problem. This technical problem
is therefore a red herring, an imagined solution problem, not the real problem.

For the real problem, the design problem, the solution adopted in Boost is to
have a mutable image class, and an immutable one. They may share some
implementation code, whatever. But by separating the concepts in 2 different
classes, the DIY 'const' solution, the code can *know* what it's dealing with.


[snip]

Cheers & hth.,

- Alf
 
F

Frank Neuhaus

Alf P. Steinbach said:
* Frank Neuhaus:
[...]
AFAIK, there is no way to achieve the above. Or is there?

You can provide both constructors.

The problem with that is that a constructor doesn't innately know whether
it's constructing an instance that will be 'const' after construction, and
furthermore it doesn't know that an image passed by reference to const is
originally const (no aliasing). So in spite of having achieved the
technical goal of channeling the const argument to specific constructor
code, essentially nothing is achieved with respect to the design problem.
This technical problem is therefore a red herring, an imagined solution
problem, not the real problem.

I was actually aware of the fact that it's semantically wrong (and not just
syntactically wrong) to have this constructor.
For the real problem, the design problem, the solution adopted in Boost is
to have a mutable image class, and an immutable one. They may share some
implementation code, whatever. But by separating the concepts in 2
different classes, the DIY 'const' solution, the code can *know* what it's
dealing with.

Ok so at the end of the day they have the same problem as I do? So they have
two different types of const images:
const_Image<unsigned char> which represents the immutable Image class and
const Image<unsigned char> which represents a const, mutable Image class?

That would mean that it's pretty much equivalent to my solution... I guess
it looks more evil than it is then...?
What I am just unhappy about is that it's not immediately clear to the user,
why he sometimes needs to use the immutable image type, and how he can in
fact use this type in the same way as a const, mutable Image type.

Thanks
Frank
 
F

Fabio Fracassi

Alf P. Steinbach said:
* Frank Neuhaus:
[...]
AFAIK, there is no way to achieve the above. Or is there?
You can provide both constructors.
The problem with that is that a constructor doesn't innately know whether
it's constructing an instance that will be 'const' after construction, and
furthermore it doesn't know that an image passed by reference to const is
originally const (no aliasing). So in spite of having achieved the
technical goal of channeling the const argument to specific constructor
code, essentially nothing is achieved with respect to the design problem.
This technical problem is therefore a red herring, an imagined solution
problem, not the real problem.

I was actually aware of the fact that it's semantically wrong (and not just
syntactically wrong) to have this constructor.
For the real problem, the design problem, the solution adopted in Boost is
to have a mutable image class, and an immutable one. They may share some
implementation code, whatever. But by separating the concepts in 2
different classes, the DIY 'const' solution, the code can *know* what it's
dealing with.

Ok so at the end of the day they have the same problem as I do? So they have
two different types of const images:
const_Image<unsigned char> which represents the immutable Image class and
const Image<unsigned char> which represents a const, mutable Image class?

That would mean that it's pretty much equivalent to my solution... I guess
it looks more evil than it is then...?
What I am just unhappy about is that it's not immediately clear to the user,
why he sometimes needs to use the immutable image type, and how he can in
fact use this type in the same way as a const, mutable Image type.

Thanks
   Frank

You should have a look at boost::gil (Generic Image Library) which
probably solves your problem quite well. There is a nice 50 min google
video tutorial about it (http://stlab.adobe.com/gil/presentation/
index.htm), as well as a pretty good documentation (http://
www.boost.org/doc/libs/1_39_0/libs/gil/doc/index.html)

Another useful Library in the same domain is VIGRA (http://hci.iwr.uni-
heidelberg.de/vigra/) which has a simmilar design, and a quite
extensive set of image processing algorithms.

HTH

Fabio
 

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,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top