torsdag den 25. november 2010

Internal protection

Yos all

I got a idea yesterday on how to guarantee that no member functions writes (or reads) to a given member variable.

Some c++ class end up being silly long (4000+ line) and no-one really have any idea of what's going on. Especially if the given class also derives from another class, is inherited by a third and used an aggregate in a fourth class. A big mess basically.

In such scenarios, you could easily be given the task of extending the class with a new type of subsystem X. I guess that any excuse could also be used.

Idea:

class BigClass
{
public:
// lotsa stuff
private:
bool m_StateOfX;
};

if we want to guarantee that the member function OnlyForX() is the only function that writes to m_StateOfX, when we can do the following (and accept some overhead):


class BigClass
{ /* bla */
private:
struct StrictX
{
public:
bool Get();
private:
bool m_StateOfX;
friend void BigClass::OnlyForX();
} m_StateOfX;
void OnlyForX();
}

if we further want to punish ourselves with templates we can also do that:

template
class Strict
{
public:
const T& Get() const { return m_Val; }
protected:
T m_Val;
};

class BigClass
{
class StrictX : public Strict { friend BigClass::OnlyForX(); };
void OnlyForX();
};

there you go! it might even compile..

4 kommentarer:

  1. It's a great idea with a friend functions. One thing that strikes me: do you really wanna clutter the declaration of BigClass with yet another internal class / struct?

    SvarSlet
  2. Rather than create more obfuscation I think (and now I know I'll create a lot of enemies in the trade) constructive comments on exactly what a variable does and when it's used is both more helpful, and takes less time.

    My solution also works in other languages, such as Java and C#! :)

    SvarSlet
  3. hey all, thanks for comments

    yep, i know that this all is complicated and not particular straightforward. But my reason for giving the example is the ungrateful "hostile environment" programming situation. Here you don't have the full picture of ownership, control or which crazy aggregate, inheritance or reinterpret_cast enables who to do what.

    The best solution is obviously control. Possibly gained via a 10 ton cluebat - with spikes. If you need any kind of performance from you code you need to batch updates together anyways. That requires actually knowing what's going on.

    SvarSlet
  4. my point is sometimes is nice to have the compiler guarantee us uniqueness. Imagine that you don't have time to fully understand the monster that has been create and you just want to guarantee that your feature works.

    I didn't apply my example to production code :D

    SvarSlet