Question

Given the following example code:

class Room {
    Room() : switch(*this) { }
    Lamp lamp;
    Switch switch;
    void TurnOn() { lamp.TurnOn(); }
}

class Switch {
    Switch(Room& room) : room(room) { }
    Room& room;
    void TurnOn() { room.lamp.TurnOn(); }
}

My understanding here is that the second TurnOn() involves an extra level of indirection, as we need to follow the reference to room. Is this correct? Will that extra indirection be removed if the call can be inlined (either via explicit inlining, or whole program optimization at linker level)? Or, put differently, could the TurnOn function in Switch be sped up by changing it to:

class Room {
    Lamp lamp;
    Switch switch;
    Room() : switch(*this,lamp) { }
    void TurnOn() { lamp.TurnOn(); }
}

class Switch {
    Room& room;
    Lamp& lamp;
    Switch(Room& room,Lamp& lamp) : room(room),lamp(lamp) { }
    void TurnOn() { lamp.TurnOn(); }
}

Or, more generally, if holding a reference to an object, is there a level of indirection less involved in accessing its members directly via a reference rather than via the reference and then the member?

Thanks

Was it helpful?

Solution

It might be faster (though not by much). However, both examples are incorrect in that they break encapsulation and violate the Law of Demeter. They require that either the Switch class or anyone who instantiates it have access to both the Room itself and the Lamp inside of it. Of course, we're also assuming that every Room has a Lamp, and that a Lamp can only ever exist within a Room...which means if those conditions ever change, there's two classes to change instead of just one.

The first example would be better written as

class Room {
  public:
    Room() : sw(*this) { }
    void TurnOn() { lamp.TurnOn(); }
  private:
    Lamp lamp;
    Switch sw;
};

class Switch {
  public:
    Switch(Room& room) : room(room) { }
    void TurnOn() { room.TurnOn(); }
  private:
    Room& room;
};

as then the Room is responsible for what gets turned on. Could be a lamp, could be a radio. Switch doesn't have to care anymore. This is more likely to be slower, but it's more maintainable.

If you want to require that Switch only turn on a Lamp, then

class Room {
  public:
    Room() : sw(lamp) { }
    void TurnOn() { lamp.TurnOn(); } // (semantics: who "turns on" a room?)
  private:
    Lamp lamp;
    Switch sw;
};

class Switch {
  public:
    Switch(Lamp& lamp) : lamp(lamp) { }
    void TurnOn() { lamp.TurnOn(); }
  private:
    Lamp& lamp;
};

This should be just as fast, without requiring that we break encapsulation.

OTHER TIPS

Your second example will (probably) be no faster than the first example. In both cases, one reference needs to be resolved before TurnOn() can be invoked.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top