C++ Best Practices

State Machine for Asynchronous Queries

When dealing with asynchronous D-Bus queries that can be triggered by external events (like InterfacesAdded), use a state machine to handle race conditions and defer events:

  • Use a querying boolean flag to protect the critical section during an active query.
  • Use an enum state (e.g., None, Add, Remove) to record events that arrive while a query is in flight.
  • When the query completes, check the recorded state and trigger a deferred query if needed (e.g., if an Add event arrived).
  • Centralize the setting and clearing of the querying flag inside the query function to avoid scattered state management.

Compare, Don't Subtract for Sentinel Time Points

Because of the guaranteed overflow, you should never perform arithmetic operations on time_point::min() or time_point::max(). They are strictly meant to be used as sentinel (flag) values.

If you need to know if an interval is valid, use equality operators (== or !=) to check the state of the variable before doing any math:

auto last_event = std::chrono::steady_clock::time_point::min();
auto current_time = std::chrono::steady_clock::now();

// ❌ WRONG: This will overflow and cause undefined behavior!
// auto elapsed = current_time - last_event;

// ✅ CORRECT: Check the sentinel value first
if (last_event != std::chrono::steady_clock::time_point::min()) {
    auto elapsed = current_time - last_event;
    // Process the elapsed time...
}

## Testing & Debugging

### Verify Mock Before Questioning Infrastructure
Before questioning Object Mapper (mapperx) performance or behavior in a testing environment, use `dbus-monitor` and `busctl` to examine the mock server implementation. The mock might be static or missing dynamic behaviors expected by the test.

### Use A/B Testing for Regressions
Use A/B testing (running specific tests with and without your changes) to narrow down which change broke what test, before claiming the test was already failing before your changes.