Skip to Content
Course content

44: Pointers and References Revisited

Click on the "Edit" button in the top corner of the screen to edit your slide content.

By this point in the course, you've used pointers and references plenty of times. But I've noticed that even experienced devs sometimes hesitate when deciding which one to use in a new function. It’s easy to memorize the syntax, but harder to internalize the intent. Let's clear that up.

Think of it like this: Imagine you have a physical house. A pointer is like a scrap of paper with the house's address written on it. You can pass that piece of paper to anyone. You can erase the address and write a different one on it. You can even have a blank piece of paper (a nullptr) that doesn't point to any house at all. A reference, on the other hand, is like a nickname for the house. If you call it "The Old Manor," that name is permanently glued to that specific building. You can't suddenly decide that "The Old Manor" now refers to the cottage down the street.

The Flexibility of the Address Slip

Because a pointer is just a variable holding an address, it's incredibly flexible. You can change what it points to on the fly. I use this all the time when I'm implementing data structures like linked lists or trees where the "current" node needs to shift constantly.

int score1 = 10;
int score2 = 20;
int* currentScore = &score1; // The paper says "House 1"

// Now I want to track the second score
currentScore = &score2; // I erased House 1 and wrote "House 2"

Notice that currentScore itself changed. We didn't change the value of the scores; we changed which score we were looking at. That's the core power of the pointer.

The Permanence of the Nickname

References are different. When you initialize a reference, you're not creating a new "object" in the way a pointer is; you're creating an alias. Once ref is bound to var, it is var for the rest of its life. If you try to "reassign" a reference, you're actually just changing the value of the original variable.

int health = 100;
int backupHealth = 50;
int& healthRef = health; // "healthRef" is now just another name for "health"

healthRef = backupHealth; // This does NOT make healthRef point to backupHealth.
// Instead, it changes the value of 'health' to 50.

This is where people usually get tripped up. If you're expecting the reference to jump to a new variable, you're in for a surprise. It's anchored. This makes references much safer and cleaner for function parameters because you don't have to worry about the reference suddenly pointing to something else mid-function.

Handling the "Empty" Case

One of the biggest deciding factors for me is whether "nothing" is a valid option. A reference must refer to something. You can't have a null reference (well, you can technically force one with some very bad hacks, but please don't). If your logic allows for the possibility that an object might not exist, you have to use a pointer.

I often use this when dealing with optional components in a game engine. For example, a Character might have a Weapon* currentWeapon. If the character is unarmed, currentWeapon is simply nullptr. If I used a reference, I'd be forced to create a "FakeWeapon" object just to satisfy the compiler, which is a messy waste of memory.

Choosing Your Tool

So, how do I decide in the heat of the moment? I follow a simple hierarchy of preference:

  • Use a reference by default for function parameters. It tells the caller, "I need an actual object to work with, and I'm not going to change which object I'm talking about."
  • Use a pointer if you need to be able to reassign the target or if "null" is a meaningful state in your logic.
  • Use a const reference (const T&) if you want the efficiency of not copying a large object, but you want to guarantee you won't accidentally modify it.



πŸ“‹ Practical Task

Building a Dynamic Equipment Linkage System

You are tasked with creating a simplified equipment system for an RPG. The goal is to demonstrate the correct use of pointers for optional items and references for core attributes.

Requirements:

  1. Create a Stat class that holds a single integer value (e.g., strength).
  2. Create an Item class that holds a name (string) and a strength bonus (integer).
  3. Create a Character class with:
    • A Stat object called baseStrength.
    • A pointer to an Item called equippedWeapon (this should be initialized to nullptr).
  4. Implement a function void calculateTotalStrength(const Character& c, int& total). This function must use a reference for the Character to avoid copying, and a reference for the total to return the calculated value.
  5. The logic for calculateTotalStrength should be:
    • Start with the character's baseStrength.
    • Check if equippedWeapon is not null. If it exists, add the weapon's bonus to the total.

Your task: Write the full implementation. In your main function, create a character, calculate their strength while unarmed, then equip a weapon (by assigning its address to the pointer) and calculate the strength again to verify the increase.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.