Skip to content
BoKSA

References and Const Correctness

References and Const Correctness

Introduction

C gave you pointers — powerful, easy to misuse (NULL, uninitialized, arithmetic errors). C++ adds references: an alias to an existing variable. They look like normal variables but must refer to something valid from birth. Combined with const, you tell the compiler and your teammates what may change — critical in multi-threaded firmware and large codebases.

This article builds on Pointers in depth and prepares you for safe parameter passing in classes.


References — alias, not copy

1
2
3
4
5
int a = 42;
int &ref = a;   /* ref is another name for a */

ref = 10;
printf("%d\n", a);  /* prints 10 */
Pointer Reference
Syntax int *p = &a; int &r = a;
Rebind to another object? Yes (p = &b) No — bound once
Can be "null"? Yes (nullptr) No — must refer to valid object
Syntax at use *p = 5 r = 5

In plain terms

A pointer is a sticky note with an address you can erase and rewrite. A reference is a nickname you tattoo at birth — "call this variable ref too," forever for that object.


References as function parameters

Avoid copying large objects:

1
2
3
4
5
6
7
struct ImuSample {
    float ax, ay, az, gx, gy, gz;
};

void filter(const ImuSample &sample) {
    /* read sample — no copy of 24 bytes */
}

Pass read-only data as const T & — efficient and documents intent.

Modify caller data — reference instead of pointer when object must exist:

1
2
3
4
5
6
7
8
void swap(int &x, int &y) {
    int t = x;
    x = y;
    y = t;
}

int a = 1, b = 2;
swap(a, b);

Same idea as C pointer version, cleaner call site. Pointers remain for optional arguments (nullptr = not provided) and hardware addresses.


const — promise not to change

1
2
3
4
void printRpm(const Motor &m) {
    printf("%.1f\n", m.getRpm());
    // m.setRpm(0);  /* error if setRpm is non-const */
}
Form Meaning
const int x x cannot change
const int &r alias to something you will not modify through r
int *const p p fixed; *p can change (C rule)
const int *p *p read-only; p can point elsewhere

Member function const:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Motor {
public:
    double getRpm() const { return rpm_; }  /* won't modify object */
    void setRpm(double r) { rpm_ = r; }
private:
    double rpm_;
};

const Motor m;
m.getRpm();   /* OK */
// m.setRpm(0);  /* error — const object needs const method or mutable */

const after ) means "this method does not modify visible object state" — enables calling on const objects and documents thread-safety hints.


References vs pointers in embedded APIs

Use reference when Use pointer when
Argument always required Optional (nullptr)
Object always valid C API interop
Clean syntax matters Register address (volatile uint32_t *)
Range / output param in C++ style DMA buffer start
1
2
3
void readAdc(int channel, uint16_t &out) {
    out = hal_adc_read(channel);
}

vs C style void read_adc(int ch, uint16_t *out).


nullptr instead of NULL

C++11 introduces nullptr — typed null pointer constant:

1
2
Sensor *s = nullptr;
if (s != nullptr) { /* ... */ }

Avoids ambiguity when NULL is #define 0 and overload resolution breaks. Use in new C++ code; C headers may still use NULL.


Const correctness discipline

  1. Default to const until you need to mutate.
  2. Pass objects by const & unless small (int, bool).
  3. Mark methods const when they only read state.
  4. mutable rare — allows changing one field inside const method (e.g. cache); use sparingly.

Firmware benefit: compiler catches accidental writes in ISR or shared read paths; code review sees intent in signatures.


Relevant topics


Starting points

  1. Refactor one void foo(LargeStruct *p) to void foo(const LargeStruct &s).
  2. Add const to three getter methods — fix compile errors in callers.
  3. Explain why int &r; without initializer is illegal.
  4. Compare generated assembly for pass-by-value vs pass-by-const-ref (often identical for pointers internally).

Focus points

  • References must be initialized — no default "empty reference".
  • Do not return reference to local variable — dangling, same as pointer.
  • const & to temporary extends lifetime of temporary in some cases — know the rule before relying on it.
  • ISR signatures often stay C pointers for clarity and volatile.

Key points

  • References are non-null aliases; syntax cleaner than pointers for required parameters.
  • const documents read-only intent; const member functions do not modify object state.
  • nullptr is the type-safe null pointer in modern C++.
  • const correctness catches bugs early and clarifies APIs in firmware teams.