views:

403

answers:

6

Hi,

I would like to create in C++ a Notifier class that I will use in other objects to notify various holders when the object gets destroyed.

template <class Owner>
class Notifier<Owner> {
public:
  Notifier(Owner* owner);
  ~Notifier(); // Notifies the owner that an object is destroyed
};

class Owner;

class Owned {
public:
  Owned(Owner* owner);
private:
  Notifier<Owner> _notifier;
};

My point is that as I have a dense and complicated object graph, I'd like to avoid storing the address of the owned object in the notifier. Is there a way to change my notifier class so that it can deduce the owned object's address from its own address and an offset that would be computed at compile time?

Note also that any object may have to notify several 'owners', possibly from the same class.

Thanks.

+1  A: 

Part of the solution would be to have Owned inherit from Notifier. This way, the address of the destroyed object is simply 'this'...

class Owned : public Notifier<Owner> {
public:
  Owned(Owner* owner) 
    : Notifier<Owner>(owner)
  {}
};

But how to handle multiple 'owners' from the same class? How can one inherit several times from the 'same class'?

Thanks to fa's answer, here is the solution I was looking for:

#include <iostream>

template <class Owner, class Owned, int = 0>
class Notifier {
public:
  Notifier(Owner* owner)
    : _owner(owner)
  {}
  ~Notifier() {
    _owner->remove(owned());
  }
  Owned * owned(){ 
    return static_cast< Owned * >( this ); 
  }

private:
  Owner* _owner;
};

class Owner {
public:
  void remove(void* any) {
    std::cout << any << std::endl;
  }
};

class Owned : public Notifier<Owner,Owned,1>, Notifier<Owner,Owned,2> {
public:
  Owned(Owner* owner1, Owner* owner2)
    : Notifier<Owner,Owned,1>(owner1)
    , Notifier<Owner,Owned,2>(owner2)
  {}
};

int main() {
  std::cout << sizeof(Owned) << std::endl;
  Owner owner1;
  Owner owner2;
  Owned owned(&owner1, &owner2);
  std::cout << "Owned:" << (void*)&owned << std::endl << std::endl;
}

Thanks!

Xavier Nodet
In the notifier, can't you store a list of owners instead of a single one?
Luc Touraille
Your use case really allows you to know all of this at compile time? And you're ok with the code bloat from instantiating so many templates?
rmeador
The use case is to implement the relations between classes in a Business Object Model. E.g. a Demand is linked to a Customer: I know all about those classes, and I know that each demand has exactly 1 customer, and that each customer has 0 to n demands...
Xavier Nodet
+6  A: 

Take a look at the GoF Observer Design Patter.

Mykola Golubyev
I'm indeed looking for a way to implement a one-to-many relationship. It can very well be used for an Observer pattern, but not necessarily.
Xavier Nodet
@Xavier: I am not sure I understand you. "very well be used for an Observer". Observer is the way you can implement your notification.
Mykola Golubyev
"The Observer defines a one-to-many relationship so that when one object changes state, the others are notified and updated automatically". But I want the many to notify the one (in a memory-efficient way).
Xavier Nodet
A: 

I highly doubt it. There is no way for the Notifier to know that it has been used in composition. What if I do

class Foo
{
private:
  Notifier _a, _b, _c;
}

I'd love to be proven wrong though, but I really doubt it's doable without explicitly giving more information to the Notifier.

unwind
Any template (or other) trick to give this information at compile-time?
Xavier Nodet
There is no way templates can help you here.
Benoît
+2  A: 

It would be a nasty hack and probably not guaranteed to work, but here's a thought I don't recommend this.

Suppose you have your layout like you described like this:

template <class Owner>
class Notifier<Owner> {
public:
  Notifier(Owner* owner);
  ~Notifier(); // Notifies the owner that an object is destroyed
};

class Owner;

class Owned {
public:
  Owned(Owner* owner);
private:
  Notifier<Owner> _notifier;
};

If _notifier knows its name, it could calculate Owned's address like this (which is executed in the Notifier's constructor):

Owned *p = reinterpret_cast<Owned *>(reinterpret_cast<char *>(this) - offsetof(Owned, _notifier));

basically, the assumption is that _notifier is at some fixed offset within the Owned class. Therefore the address of Owned is equal to _notifier's address minus that same offset.

Once again, this is undefined behavior which I wouldn't recommend, but could possibly work.

Evan Teran
+2  A: 

Or something like this :

Inherit from your notifier and add Owned as template parameter. Then you can have a owned method available inside the notifier :

template < class Owner , class Owned >
class Notifier
{
public:
    Notifier(Owner* owner)
    {}

    Owned * owned()
    { return static_cast< Owned * >( this ); }

    ~Notifier()
    {
        // notify owner with owned()
    }
};

class Owner
{};

class Owned : public Notifier< Owner , Owned >
{
public:
    Owned( Owner * owner ) : Notifier< Owner , Owned >( owner )
    {}
};
fa.
+1. That's in my opinion the best solution. However, it doesn't allow multiple owners of the same type.
Luc Touraille
@Luc: Yes, it does allow multiple owners of the same type with just a bit more work: adding e.g. an int template parameter... See my answer.
Xavier Nodet
This solution is only applicable if the object graph is nearly static (not more than one object of the same type). If you create instances dynamically in a tree-like manner you need the instances of the owner to be stored.
rstevens
This is the Curiously Recurring Template Pattern (CRTP): http://c2.com/cgi/wiki?CuriouslyRecurringTemplate
Xavier Nodet
+3  A: 

fa.'s answer is a good start. However, it does not resolve the problem of having multiple owners of the same type. One solution is to have the notifier store a list of owners instead of a single one. Here is a quick implementation, to show the idea:

template <typename Owner, typename Owned>
class Notifier
{
  protected:
    Notifier()
    {}

    // Constructor taking a single owner
    Notifier(Owner & o) 
    { 
        owners.push_back(&o); 
    }

    // Constructor taking a range of owners
    template <typename InputIterator>
    Notifier(InputIterator firstOwner, InputIterator lastOwner)
        : owners(firstOwner, lastOwner) {}

    ~Notifier()
    {
        OwnerList::const_iterator it = owners.begin();
        OwnerList::const_iterator end = owners.end();
        for ( ; it != end ; ++it)
        {
            (*it)->notify(static_cast<Owned*>(this));
        }
    }

    // Method for adding a new owner
    void addOwner(Owner & o) 
    { 
        owners.push_back(&o); 
    }

private:
    typedef std::vector<Owner *> OwnerList;
    OwnerList owners;
};

You can use it this way:

class Owner;

class Owned : public Notifier<Owner, Owned>
{
    typedef Notifier<Owner, Owned> base;

    //Some possible constructors:
    Owned(Owner & o) : base(o) { }

    Owned(Owner & o1, Owner & o2)
    {
        base::addOwner(o1); //qualified call of base::addOwner
        base::addOwner(o2); //in case there are other bases
    }

    Owned(std::list<Owner*> lo) : base(lo.begin(), lo.end()) { }
};

In the case where you have many different types of Owners, this solution can become rather difficult to use. In this case, you might want to look at the boost metaprogramming libraries (MPL, Fusion), with which you could end up with a code that let you do stuffs like that:

class Owned : public Notifier<Owned, OwnerType1, OwnerType1, OwnerType2>
{
    Owned(OwnerType1 & o1, OwnerType1 & o2, OwnerType2 & o3) 
        : base(o1,o2,o3)
};

However, implementing this solution would be a little longer than the previous one.

Luc Touraille
This is very interesting if one needs a dynamic list of owners. In my case, I know beforehand how many owners I have of each type (usually one, sometimes two, never more).
Xavier Nodet