2

What I am trying to do is create a base class, for which anything derived from it will automatically be registered with another class, eg:

class System;
class Object
{
public:
    Object()
    {
        System sys;
        sys.AddObject(this);
    }
    virtual ~Object()
    {
        System sys;
        sys.RemoveObject(this);
    }
};
class System
{
public:
    // Some other processing function which operates on all things derived
    // from Object at one time.
    void ProcessAllObjectsInExistence();

    void AddObject(Object *o)
    {
        list.push_back(o);
    }
    void RemoveObject(Object *o)
    {
        std::vector<Object *>::iterator i = find(list.begin(), list.end(), o);
        if (*i != list.end()) list.erase(i);
    }
private:
    static std::vector<Object *> list;
};

Is this legal and defined? The reason why I am asking is because I am getting some funny errors after reading and writing to the data members of Object (not shown here) from inside ProcessAllObjectsInExistence().

i.e. for a single Object before I call System.ProcessAllObjectsInExistence() the members are 0 and 100, and then the first line inside ProcessAllObjectsInExistence() is a debugging line which prints the members and displays 0 and 0. painful ><

Bingo
  • 3,785
  • 6
  • 23
  • 27
  • 1
    May I ask why you didn't make the `AddObject` and `RemoveObject` static as well? If they only use the static `list` variable then I see no reason they couldn't be static as well. – Some programmer dude Feb 15 '12 at 09:34
  • Is this complete? Does the constructor of `Object` do something that could throw, *after* adding itself to the list? @Joachim: it's called the "Borg" pattern, at least that's what Alex Martelli called a particular version of it in Python. – Steve Jessop Feb 15 '12 at 09:40
  • 1
    @JoachimPileborg The hidden static and the different instances of `System` is confusing. If he's going this route, then `System` should be a singleton, to express clearly that there really is only one effective instance. (Whether having just one instance, as he's doing, is appropriate is another question. One for which we don't have enough information to judge.) – James Kanze Feb 15 '12 at 09:57
  • I thought it was called the monostate pattern myself. – Bingo Feb 15 '12 at 09:57
  • @Bingo: indeed, http://c2.com/cgi/wiki?MonostatePattern, http://code.activestate.com/recipes/66531-singleton-we-dont-need-no-stinkin-singleton-the-bo/. James and Joachim find it confusing compared with Singleton, others find it less confusing. You basically can't win with global mutable state, someone is going to tell you you're doing it wrong, but if you called the class `SystemHandle` rather than `System`, then that alone might help people realise that the purpose of the object is to access the shared state, rather than to contain it. – Steve Jessop Feb 15 '12 at 12:15
  • @SteveJessop thanks, that sounds like good advice. – Bingo Feb 18 '12 at 05:53

2 Answers2

4

Yes, it is well defined to access this when constructing a base class.

One thing to be aware of is that, during a constructor (or a destructor) the type of *this is the class currently under construction, not the type that the fully-constructed object will eventually have. The main implication of this is that virtual functions will be dispatched according to their definitions in the base class, and it's not valid to call a pure virtual function.

Certainly, calling AddObject is fine, since it's not accessing the object under construction at all. The only way I can see your code going wrong is if you're calling ProcessAllObjectsInExistence() from a different thread while constructing an object - which would be very bad, since there's no lock to protect access to the list.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • You can call a pure virtual function as long as it [has an implementation](http://stackoverflow.com/questions/2089083/), right? – fredoverflow Feb 15 '12 at 10:48
  • @FredOverflow: Only if you call it statically (`Base::fn()`). Calling it virtually (just `fn()`) is always undefined behaviour. – Mike Seymour Feb 15 '12 at 11:06
3

It is perfectly valid to refer to this inside a Base class.
However, calling virtual methods(if you have any) inside the Base class won't actually work the way you think it should.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
Alok Save
  • 202,538
  • 53
  • 430
  • 533