92. Hardware Timer Default Constructor

Create a class HardwareTimer that represents a simple MCU hardware timer.
The default constructor must initialize all internal values to safe, reset-like defaults.

Your class must include:

  • Private members
    • int frequency
    • bool enabled
    • int prescaler
  • Constructor behavior
    • The default constructor must set:
      • frequency = 0
      • enabled = false
      • prescaler = 1
    • These values represent a safe reset state:
    • Timer disabled
    • Prescaler at minimum valid value
    • No active frequency
  • Public methods
    • void configure(int freq, int pre)
      • Sets frequency = freq
      • Sets prescaler = pre
      • Enables the timer
    • void stop()
      • Disables the timer
    • void print()
      • Prints the timer state in the format:
      • F=<frequency> P=<prescaler> EN=<0 or 1>

In main()

  1. Create a HardwareTimer object using the default constructor
  2. Read integers f and p
  3. Call configure(f, p)
  4. Read integer flag x
    • If x == 0, call stop()
  5. Print the final timer state using print()

 

Example 1

Input:

1000 8
1 

Output:

F=1000 P=8 EN=1 

 

Example 2 

Input:

500 4
0

Output:

F=500 P=4 EN=0 

 

Constraints

  • The default constructor must be correctly implemented
  • All internal values must match the required defaults
  • Output formatting must match exactly

 

 

 

Need Help? Refer to the Quick Guide below

A Constructor is a special member function that runs automatically when an object is created. Its purpose is to guarantee that the object starts in a valid state (e.g., pointers assigned, hardware initialized, invariants checked) before any other code uses it.

It has no return type and shares the same name as the class.

Syntax & Usage

1. Basic & Parameterized Constructors

The most common forms used to initialize variables.

class GPIO {
    int pin;
public:
    // 1. Default Constructor (No args)
    GPIO() { pin = 0; }

    // 2. Parameterized Constructor (With args)
    GPIO(int p) { pin = p; }
};

GPIO led;        // Calls GPIO()
GPIO motor(9);   // Calls GPIO(int)

2. Member Initializer Lists (Crucial for Efficiency)

Initializes variables before the constructor body runs. This is mandatory for const members and References, and avoids "double-writing" variables.

class Sensor {
    const int id;
    int& bus_ref;
public:
    // Syntax: : member(value), member(value)
    Sensor(int i, int& bus) : id(i), bus_ref(bus) { 
        // Body is empty; work is already done.
    }
};

3. Advanced Variants (explicit, Copy, delete)

These control how objects are created or copied, preventing dangerous bugs.

  • explicit: Prevents accidental implicit conversions (e.g., passing int where a Driver object is expected).
  • Copy Constructor: Defines how to clone an object (crucial for Deep Copies of pointers).
  • = delete: Disables a constructor (used for Singletons or unique hardware drivers).
class Driver {
    int* buffer;
public:
    // PREVENT implicit conversion from int to Driver
    explicit Driver(int size) { buffer = new int[size]; }

    // CUSTOM Copy Constructor (Deep Copy)
    Driver(const Driver& other) {
        buffer = new int[10]; 
        memcpy(buffer, other.buffer, 10 * sizeof(int));
    }

    // DISABLE Copying entirely (Common for hardware drivers)
    // Driver(const Driver&) = delete; 
};

Initialization vs Assignment Flow

FeatureAssignment (Inside Body)Initializer List (: x(10))
MechanismVariable created (default), then overwritten.Variable created with value.
PerformanceSlower (Two steps).Faster (One step).
ConstraintsCannot init const or Reference.Required for const/Reference.

Relevance in Embedded/Firmware

1. Impossible-to-Forget Initialization

In C, forgetting UART_Init() crashes the system. 

In C++, constructors force you to provide configuration (e.g., Baud Rate) at creation time. The object never exists in an uninitialized state.

2. RAII (Resource Acquisition Is Initialization)

The "Scope Lock" pattern: A constructor acquires a resource (disables interrupts, takes a mutex), and the Destructor releases it.

{
    InterruptLock lock; // Constructor: __disable_irq();
    // Critical Section
} // Destructor: __enable_irq(); automatic at end of scope.

3. Unique Hardware Access

Using = delete on copy constructors ensures you don't have two software objects trying to control the same physical UART peripheral, preventing race conditions.

Common Pitfalls (Practical Tips)

PitfallDetails
❌ Heavy WorkAvoid complex hardware delays or checks in constructors for Global/Static objects. They run before main(), which can make the system appear to hang at boot.
❌ Initializer Order

Members are initialized in the order they are declared in the class, NOT the order in the list.

class A { int y; int x; A(): x(1), y(x) {} } reads uninitialized memory because y is declared first.

❌ Implicit ConversionWithout explicit, void func(Driver d) can be called as func(100), silently creating a 100-byte driver. This is confusing and dangerous.
✅ Default ConstructorIf you define any constructor, the compiler removes the default (empty) one. You must explicitly add GPIO() = default; if you still need it.