As a computer science student, I once learned about data structures, C language, linked lists, stacks, queues… But to be honest, over time, I almost forgot everything.
This semester, I started learning C++, and I decided not to “grind through the textbooks” anymore, but to let GPT be my “companion AI tutor” to gradually rebuild my “programmer brain”.
This series documents my learning process, hoping to help fellow confused students see:
If you don’t understand, just ask. If you can’t grasp it, take it slow. And AI can be your most patient teacher.
Today, while studying C++, I found myself staring blankly at the struct Node in the course materials.
I suddenly had a thought:
“Since we are learning object-oriented programming, why are we still writing structs?”
So I decided to challenge myself – to rewrite the entire linked list using a class.
From Struct to Class: The First “Style Awakening”
Initially, my implementation was quite traditional:
struct Node { int data; Node* next;};
Later, I added encapsulation and a constructor, rewriting it as follows:
class Node {private: int data; Node* next;public: Node(int val) : data(val), next(nullptr) {} void setNext(Node* p) { next = p; } Node* getNext() const { return next; } int getData() const { return data; }};
Functionally, there was no change, but at that moment, I was a bit moved by my own work –
Previously, I only cared about “where the pointer points”; now I began to care about “the relationships between objects”.
This is the essence of object-oriented programming:
To encapsulate details, making logic cleaner.
A Classic Question: Why Not Delete newNode at the End?
While implementing the insert function, I wrote the following:
void LinkList::insert(int pos, int value) { Node* newNode = new Node(value); ... newNode->setNext(p->getNext()); p->setNext(newNode);}
Then I hesitated: “Should I delete newNode at the end?”
GPT told me something that left a deep impression:
“It has already been taken over by the linked list,
its life no longer belongs to you.”
Indeed, at that moment, it was already linked in the list,
its memory lifecycle was no longer controlled by me, but by the entire LinkList class.
This made me truly feel for the first time:
Pointers are not just tools; they are responsibilities.
New Friend: Iterator
After rewriting the linked list, I started to explore STL’s std::list.
When I first saw the term iterator, I thought it was just a “pointer with a different name” in C, until I saw this code:
list<int>::iterator it = nums.begin();while (it != nums.end()) { cout << *it << " "; ++it;}
Then I realized it is actually a “safe pointer proxy”.
If pointers are like running naked in memory, then iterators are like little pointers wearing protective gear.
Later, I discovered that C++11’s auto could make it even more elegant:
for (auto it = nums.begin(); it != nums.end(); ++it) cout << *it << " ";
At that moment, I suddenly laughed –
Previously, I was afraid of “long types”; now the compiler helps me “guess”.
C++’s “complexity” that once scared me sometimes gently shares the burden.
Advance: The Trap of Names
When I wrote:
advance(it, 2);
I was thinking about “advance means to move forward”, but it actually made the iterator move two steps back.
I was confused.
Later, I understood that “advance” does not refer to the visual “forward” direction
but rather the “natural traversal direction of the container”.
In a linked list, this direction is “from head to tail”.
The easiest place for programming languages to deceive you is not logic, but names.
We think we understand “advance”,
but in reality, we are just reading code with our native language.
The Secret of erase’s Return Value: Why Can It Be Assigned to it?
This line of code must have confused many beginners:
it = nums.erase(it);
I was too.
Until I learned that erase() does not just “delete a node”; it also returns the next valid iterator.
In other words, it deletes while also handing you the “new route”.
You think it erased something,
but in fact, it is helping you move forward.
STL is designed so elegantly –
it allows you to delete while ensuring you don’t get lost.
Lambda Capture: Taking the “Key” Out
When I used Lambda for sorting, the following code fascinated and confused me:
int limit = 10;auto check = [limit](int x){ return x > limit; };
After asking GPT, I learned what the [] is for –
It is a “pocket for carrying external variables”.
Lambda is a temporary function that runs out to execute; if it wants to use external variables, it must pack them in advance.
You need to go out (execute the function),
and you need to use the key from home (external variable),
so you must first put the key in the pocket (capture).
At that moment, I suddenly burst out laughing –
It turns out C++ also has metaphors for life.
Conclusion
Writing a linked list gave me a sense of “my vision being broadened”.
Previously, I thought programming was about reasoning with the computer;
now I feel more like I am conversing with the designer.
Behind every keyword, there is actually a human thought:
iterator pursues safety,
auto reduces burden,
erase continues the path,
lambda teaches us to carry the world.
The process of learning C++ may be about learning –
How to make complex systems gentle and controllable.
📮 Interaction
If you are also learning C++, feel free to write your:
One confusion (a point you don’t understand)
One gain (a point you suddenly understood today)
I will compile the most representative questions into a “Reader Q&A”.