← Back to list

Understanding the MemBot Project

Udacity C++ Memory Management — Project Walkthrough (Part 1)

Seulgie Han · 2026-01-15 17:31 · 2 claps · 3.4 min read
#c-plus-plus-language #memory-management #chatbot-design
Open on Medium ↗
Wiki topics: BIZ · Business Strategy

Understanding the MemBot Project

Udacity C++ Memory Management — Project Walkthrough (Part 1)

MemBot project is part of Udacity’s C++ Memory Management course. At first glance, it looks like a chatbot project. But in reality, this is not an AI project. This project is about memory ownership, object lifetime, and move semantics in C++.

The chatbot logic itself is already implemented in the project template. The real job is to:

  • Understand who owns what
  • Decide where memory should live
  • Make sure objects are moved, not copied
  • Prevent memory leaks and double deletes

I’m writing this post as a study recap, because you cannot safely write modern C++ unless you fully understand the existing structure.

High-Level Concept: What is MemBot?

MemBot works by navigating a knowledge graph.

Core idea

  • Each GraphNode contains chatbot answers
  • Each GraphEdge represents a transition between answers
  • The ChatBot moves from node to node based on user input

Think of like this:

User Input
   ↓
ChatBot
   ↓
GraphNode (current answer)
   ↓
GraphEdge (matched by keyword)
   ↓
Next GraphNode

This design allows us to practice pointer ownership and move semantics in a realistic object graph.

Project Structure Overview

Here are the most important source files:

src/
├── chatbot.cpp / chatbot.h
├── chatlogic.cpp / chatlogic.h
├── graphnode.cpp / graphnode.h
├── graphedge.cpp / graphedge.h
└── main_cli.cpp

Let’s quickly define responsibilities before diving deeper.

  • ChatBot: Represents the chatbot agent
  • ChatLogic: Loads graph, manages overall flow
  • GraphNode: Stores answers and edges
  • GraphEdge: Connects nodes using keywords
  • main_cli: Starts terminal interaction

The Knowledge Graph (Big Picture)

The chatbot’s “brain” is stored in a text file, which looks like this:

<TYPE:NODE><ID:0><ANSWER:Hello, my name is MemBot>
<TYPE:NODE><ID:1><ANSWER:Let’s talk about memory>
<TYPE:EDGE><ID:0><PARENT:0><CHILD:1><KEYWORD:memory>

This gets converted into a graph in memory:

+---------+      Edge (keyword: memory)      +---------+
| Node 0  | ------------------------------> | Node 1  |
| Answer  |                                  | Answer  |
+---------+                                  +---------+

Nodes do not own each other, edges connect nodes, and ownership flows downward. This is crucial later when we apply smart pointers.

ChatBot Class — The “Traveler”

ChatBot receives messages from the user, asks ChatLogic to send responses and moves between nodes using move semantics. It does not own the graph, delete nodes, or create edges. That is, ChatBot does not own anything here. It only points to existing objects. This avoids circular ownership and keeps lifetimes simple.

class ChatBot {
private:
    GraphNode *_currentNode; // not owned
    GraphNode *_rootNode;    // not owned
    ChatLogic *_chatLogic;   // not owned
};

Rule of Five (Why It Matters Here)

The ChatBot class implements the Rule of Five:

  1. Destructor
  2. Copy constructor
  3. Copy assignment
  4. Move constructor
  5. Move assignment

Each function prints a message like:

>>> Rule of Five Component: ChatBot Move Constructor <<<

Why is this useful?

Because later, when the ChatBot moves between nodes, you can visually confirm:

  • Was it copied? -> Copying would be dangerous
  • Or was it moved? -> Moving is safe and intended

ChatLogic — The Graph Manager

ChatLogic is the central controller. What ChatLogic does?

  • Reads the file
  • Creates all nodes and edges
  • Identifies the root node
  • Connects the ChatBot to the graph
  • Sends messages between ChatBot and UI
class ChatLogic {
private:
    std::vector<GraphNode *> _nodes; // owns nodes
    GraphNode *_currentNode;         // not owned
    ChatBot *_chatBot;               // not owned
};

Ownership rule

  • ChatLogic owns all GraphNodes
  • ChatLogic does NOT own ChatBot
  • ChatLogic does NOT own edges directly (this changes later)

This design prevents double deletion and centralizes graph creation.

GraphNode— The Answer Holder

Each GraphNode contains:

  • A list of answers
  • Edges to parent nodes (incoming)
  • Edges to child nodes (outgoing)
  • Possibly the ChatBot (temporarily)
class GraphNode {
private:
    std::vector<GraphEdge*> _childEdges;  // outgoing
    std::vector<GraphEdge*> _parentEdges; // incoming
    ChatBot *_chatBot;                    // not owned
};

Why this structure?

  • Nodes must know where they can go next
  • Nodes must know who can lead to them
  • Only one node at a time holds the ChatBot

Later, this class will enforce exclusive ownership of outgoing edges.

GraphEdge — The Connector

GraphEdge represents possible transitions.

What an edge contains?

  • Parent node (non-owning)
  • Child node (non-owning)
  • Keywords used for matching
  • Edge ID
class GraphEdge {
private:
    GraphNode *_parentNode; // not owned
    GraphNode *_childNode;  // not owned
    std::vector<std::string> _keywords;
};

Edges do not own nodes. Nodes will eventually own edges. This avoids circular ownership like:

Node owns Edge
Edge owns Node ❌ (bad)

Memory Ownership Map (So Far)

Here’s the big picture.

ChatLogic
 ├── owns → GraphNode 0
 │     ├── outgoing → GraphEdge 0
 │     └── incoming ← none
 ├── owns → GraphNode 1
 │     ├── incoming ← GraphEdge 0
 │     └── outgoing → ...
 └── references → ChatBot

ChatBot:

ChatBot
 ├── currentNode (pointer)
 ├── rootNode (pointer)
 └── chatLogic (pointer)

No cycles. No ambiguity. Clean ownership.

What we are NOT Required to Understand

At this point, we do NOT need to deeply understand:

  • Levenshtein distance implementation
  • Keyword matching logic
  • NLP-style decision making

Those parts already work. The project is focused on memory correctness, not chatbot intelligence.

Instead, youshould understand:

  • Why ownership matters
  • Why move semantics are required
  • Why raw pointers are still used in some places
  • Where smart pointers make sense

If you don’t, you’ll end up with:

  • Dangling pointers
  • Double deletes
  • Segmentation faults

In Part 2, we will:

  • Redesign ownership using unique_ptr
  • Explain incoming & outgoing edge ownership
  • Show how ChatBot moves between nodes
  • Add move semantics diagrams

Once Part 2 is done, filling TODOs will feel not scary :)


메타데이터
post_id
ddfdad7affab
slug
understanding-the-membot-project-ddfdad7affab
url
https://medium.com/@su-paris/understanding-the-membot-project-ddfdad7affab
canonical_url
https://medium.com/@su-paris/understanding-the-membot-project-ddfdad7affab
author_url
https://medium.com/@su-paris
status
ok
fetched_at
2026-07-13 09:35:19