Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforce constness for pointed data in C++?

Let there be a Foo class with some const and non-const methods

struct Foo
{
    Foo ();
    ~Foo();

    void noSideEffect() const;
    void withSideEffect();

};

I also have a Bar class, that need to refer to Foo in some way. To be more precise, maybe too precise for this question, Bar implements operators || and && for union and intersections, so two Bar instances need to kwow they are working on the same instance of Foo.

The simplest solution I found was to use a pointer to a Foo object:

struct Bar
{

   Foo * p_foo;

   Bar (Foo& foo)
     : p_foo(&foo) {};

}

Now two bar instances can play together and see if they are both handling the same Foo. I'm almost happy.

But now I would like to sometimes use Bar with const Foo instances. Well, it might be easy, I just have to create a const Bar instance, right? There we go:

const Bar createBarFromConstFoo(const Foo& foo)
{
   Foo* newfoo = const_cast<Foo*>(&foo);
   const Bar newbar (*newfoo);
   return newbar;
}

And now the nightmare begins (see Why doesn't C++ enforce const on pointer data?). I think I understand the why (the standard says so), my main problem is how to best cope with it.

Except this little standard thing, the createBarFomConstFoo does almost what I want since it is returning a const Bar. Is there a way to prevent a const Bar to do nasty things with my (initially) const Foo (ie only call const methods of Foo) while allowing a non-const Bar to do everything?

Maybe there is no way to do that and it's an object design issue, but I do not see a simple alternative.

Edit: to downvoters, can you please explain why, I may be able to progress from your remarks...

Edit 2: Maybe obfuscating the real classes behing Foo and Bar was a bad idea, I just wanted to simplify things.

So Foo is in fact a Molecule (and in fact a Protein), which contains Atoms (many for a protein). Being able to select some atoms is the reason to create Bar, which is a SelectionOfAtoms.

It is sometimes convenient to select, from example, all hydrogens and oxygen atoms, so Bar implements unions and intersections. I want to be able to extract those atoms so SelectionOfAtoms implements a createNewMolecule() methods from the selected atoms. It therefore need a way to refer to the original molecule (maybe some kind of copy would do here but maybe not with the other requirements below).

But I recently felt the need to modify atoms of a selection, while keeping other atoms unmodified. Doing it through SelectionOfAtoms (Bar) was conveninent: it already knows where to find the Atoms (using the pointer) and the index of these atoms (internal implementation detail), so everything needed to change atoms is almost already here, except that I can either use Selection only on Molecule (non-const) or work on const Molecule and forget about modifying them or go into the const_cast horror.

I'm sure it's a pretty bad design, but it is what is already there, it can surely be improved a lot.

like image 439
ascobol Avatar asked Nov 02 '22 00:11

ascobol


1 Answers

Using the STL as a guide, consider your molecule as a container, and your selection as something like an iterator or iterator range.

Now, in this scheme you'd have separate types for the const and non-const selections/iterators, which makes sense since they have different semantics. Making the constness a template parameter is probably a false economy unless there's a lot more code in the selection than you've suggested.

Now, you start off with either a const or a non-const molecule, and you know statically that you're getting ether a const_selection or (non-const) selection.

like image 132
Useless Avatar answered Nov 15 '22 03:11

Useless