Understanding the MemBot Project — Ownership, Move Semantics, and Graph Design
Udacity C++ Memory Management — Project Walkthrough (Part2)
Understanding the MemBot Project — Ownership, Move Semantics, and Graph Design
Udacity C++ Memory Management — Project Walkthrough (Part2)
In Part 1, we focused on what the project looks like. In Part 2, we focus on why it is designed this way. If you try to “just fill in the TODOs”, you will almost certainly:
- break ownership rules
- leak memory
- or accidentally copy objects that must be moved
Let’s state the most important rule upfront:
At any point in time, every object must have exactly one clear owner.
This applies to:
- GraphNodes
- GraphEdges
- ChatBot
Everything else uses non-owning raw pointers. Before touching code, we must clearly separate Ownership vs Access. Ownership means responsible for deleting the object, whereas Access means the availability to use the object / must NOT delete it. In this project:
- GraphNode is owned by ChatLogic
- GraphEdge is owned by GraphNode (parent side)
- ChatBot is owned by Moves between GraphNodes
Everyone else only borrows pointers.
Understanding ChatBot
Understanding ChatBot ownership is crucial in this project. Ownership Structure:
- The root GraphNode owns the ChatBot — Root Node creates and manages the ChatBot object
- ChatLogic does NOT own the ChatBot — it only holds a pointer (
_chatBot) to interact with it. Just has a pointer; does not delete or manage - Other GraphNodes only reference the ChatBot temporarily as it moves along the graph.
Why this design?
- There should always be only one ChatBot — no two nodes can own it at the same time.
- Move semantics allow the ChatBot to safely travel from one side to another.
- Clear ownership — root node manages lifetime, so no double deletion occurs.
If ChatBot were copied instead of moved, two nodes could think they own the chatbot, and both would try to talk and control state. This violates single responsiblity and single ownership. Move semantics guarantee:
After moving, the source object is empty and safe.
How It Works in Code
// Root node creates ChatBot
ChatBot chatBot("../images/chatbot.png");
_chatBot->SetRootNode(rootNode);
// Moving the ChatBot to a new node
_currentNode->MoveChatbotToNewNode(newNode);
MoveChatbotToNewNodeusesstd::move(_chatbot)- Previous node
_chatBotbecomesnullptr - New node temporaily references the ChatBot but does not own it
ChatBot Movement Flow (Step-by-Step)
Let’s trace a typical user interaction.
Step 1: User sends a message
ChatLogic::SendMessageToChatBot("What is a pointer?");
Step 2: ChatBot processes input
ChatBot::ReceiveMessageFromUser(...)
Step 3: Current node transfers ChatBot
_currentNode->MoveChatbotToNewNode(newNode);
Step 4: Ownership transfer happens
newNode->moveChatbotHere(std::move(_chatBot));
std::move does NOT move by itself. It enables the move constructor.
Why Rule of Five Is Tested Here
ChatBot implements:
ChatBot(ChatBot &&source);
ChatBot &operator=(ChatBot &&source);
These functions transfer internal pointers, reset the source object, and avoid double references. The printed log messages exist so you can verify moves happen.
The ChatBot Does Not Own ChatLogic
This is subtle but crucial.
_chatLogic->SetChatbotHandle(this);
This creates a two-way connection. ChatBot knows ChatLogic and ChatLogic knows ChatBot. But neither owns the other. Why is this safe? Because both objects live for the duration of the program, and lifetime is controlled externally (main).
The main_cli.cpp is simple. As the CLI entry point, it only creates ChatLogic, load graph, and start loop. This is intentional. Memory complexity belongs inside the graph, not in main.
In GraphNode:
std::vector<GraphEdge*> _parentEdges;
This vector does NOT delete edges, only exists to answer questions like “How many parents does this node have?” — If child nodes owned incoming edges, that will lead to double deletion.
Key Takeaways
- Owner: Root Node
- References: ChatLogic and all other GraphNodes
- Behavior: Only one ChatBot exists at a time, moving safely along the graph
Avoid to:
- use
shared_ptreverywhere - Copy ChatBot instead of moving
- Let both nodes own the same edge
- Delete objects manaually “just in case”
Before touching any TODO, answer these questions:
- Who owns this object?
- Who deletes it?
- Can it be copied safely?
- Should it be moved instead?
- Is this pointer owning or non-owning?
Final Ownership Diagram (Target Design)
ChatLogic
├── owns → GraphNode
│ ├── owns → GraphEdge
│ │ └── points to → GraphNode
│ └── non-owning ← GraphEdge
└── references → ChatBot
ChatBot
├── currentNode (non-owning)
├── rootNode (non-owning)
└── chatLogic (non-owning)
Single ownership everywhere. Zero ambiguity.
In the next post, we will finally:
- Fill in all TODOs
- Convert ownership to
unique_ptrwhere required - Implement safe move logic
- Validate against the project rubric
At that point, this project stops being “confusing” and becomes mechanically logical.
메타데이터
- post_id
- 8dcc259c657d
- slug
- understanding-the-membot-project-ownership-move-semantics-and-graph-design-8dcc259c657d
- url
- https://medium.com/@su-paris/understanding-the-membot-project-ownership-move-semantics-and-graph-design-8dcc259c657d
- canonical_url
- https://medium.com/@su-paris/understanding-the-membot-project-ownership-move-semantics-and-graph-design-8dcc259c657d
- author_url
- https://medium.com/@su-paris
- status
- ok
- fetched_at
- 2026-07-13 08:54:12