98. Clock-Dependent Peripheral Design

#include <iostream>
using namespace std;

class ClockController {
public:
    ClockController() {
        cout << "Clock enabled" << endl;
    }

    ~ClockController() {
        cout << "Clock disabled" << endl;
    }

    void write(int offset, int value) {
        cout << "Clocked write: " << offset << " " << value << endl;
    }
};

class Peripheral {
private:
    ClockController& clk;

public:
    Peripheral(ClockController& c) : clk(c) {
        cout << "Peripheral ready" << endl;
    }

    ~Peripheral() {
        cout << "Peripheral stopped" << endl;
    }

    void writeReg(int offset, int value) {
        clk.write(offset, value);
    }
};

class Driver {
private:
    ClockController clk;
    Peripheral periph;

public:
    Driver() : periph(clk) {
        cout << "Driver started" << endl;
    }

    void operate(int offset, int value) {
        periph.writeReg(offset, value);
    }

    ~Driver() {
        cout << "Driver stopped" << endl;
    }
};

int main() {
    int offset, value;
    cin >> offset >> value;

    {
        Driver drv;
        drv.operate(offset, value);
    }

    return 0;
}

Explanation & Logic Summary:

This problem demonstrates dependency-aware composition, where one component cannot function unless another component is already active.

The Driver owns the ClockController, making it responsible for enabling and disabling the clock.
The Peripheral does not own the clock; instead, it depends on an existing clock instance via a reference.

Because references:

  • Must be initialized at construction
  • Cannot be null
  • Cannot be reseated

the following guarantees are enforced:

  • The peripheral cannot exist without a clock
  • The clock must be created before the peripheral
  • The peripheral can never use an invalid clock

Constructor order guarantees safe startup:

  • Clock enabled
  • Peripheral ready
  • Driver started

Destructor order guarantees safe shutdown:

  • Driver stopped
  • Peripheral stopped
  • Clock disabled

Firmware Relevance & Real-World Context:

On real microcontrollers, peripherals such as UART, SPI, I2C, timers, and ADCs require their clocks to be enabled before any register access.

Violating this rule can cause:

  • Ignored writes
  • Bus faults
  • System lockups or resets

By encoding hardware dependencies directly into C++ class relationships:

  • Invalid states become impossible to express
  • Initialization and shutdown order is deterministic
  • Entire classes of low-level firmware bugs are eliminated

This makes dependency-aware composition a core embedded C++ design skill.

 

 

 

 

 

Loading...

Input

8 55

Expected Output

Clock enabled Peripheral ready Driver started Clocked write: 8 55 Driver stopped Peripheral stopped Clock disabled