C++ To-Do List App Project
Add, list, complete, and delete tasks — saved to a file so they survive restarts.
What you will build
A task manager for the terminal: add tasks, mark them done, delete them, and save everything to a text file so the list is still there tomorrow. It's most people's first taste of real data modelling — a struct, a collection, and persistence — in one small program.
What you will learn
- Defining a struct to model a task
- Storing objects in std::vector
- Saving and loading data with file streams
- Numbering, searching, and removing items
Feature checklist
- Add a task with a description
- List tasks with done / not-done status
- Mark a task complete by number
- Delete a task by number
- Auto-save to a file and reload on startup
Starter code
#include <iostream>
#include <vector>
#include <string>
struct Task {
std::string text;
bool done = false;
};
int main() {
std::vector<Task> tasks;
int choice;
do {
std::cout << "\n1) Add 2) List 3) Complete 4) Delete 0) Quit\n> ";
std::cin >> choice;
std::cin.ignore();
if (choice == 1) {
Task t; std::cout << "Task: ";
std::getline(std::cin, t.text);
tasks.push_back(t);
} else if (choice == 2) {
for (size_t i = 0; i < tasks.size(); ++i)
std::cout << i + 1 << ". [" << (tasks[i].done ? "x" : " ")
<< "] " << tasks[i].text << "\n";
} else if (choice == 3) {
size_t n; std::cout << "Task number: "; std::cin >> n;
if (n >= 1 && n <= tasks.size()) tasks[n - 1].done = true;
} else if (choice == 4) {
size_t n; std::cout << "Task number: "; std::cin >> n;
if (n >= 1 && n <= tasks.size())
tasks.erase(tasks.begin() + (n - 1));
}
} while (choice != 0);
}Full walkthrough
Step 1: Model a task as a struct
A task is two facts glued together — what it says and whether it is finished — so the starter defines struct Task { std::string text; bool done = false; }. The '= false' default means a freshly created task is never accidentally 'done'. All tasks live in a std::vector<Task> tasks, which grows as the user adds items.
Step 2: Build the menu loop
main() runs a do/while that prints '1) Add 2) List 3) Complete 4) Delete 0) Quit', reads an int choice, and repeats until choice is 0. A do/while (not a plain while) guarantees the menu shows at least once. Notice std::cin.ignore() right after reading the choice — it eats the leftover newline so the next getline does not read an empty string.
do {
std::cout << "\n1) Add 2) List 3) Complete 4) Delete 0) Quit\n> ";
std::cin >> choice;
std::cin.ignore(); // swallow the leftover newline
// ... handle the choice ...
} while (choice != 0);Step 3: Add and list tasks
Adding is: create a Task, prompt 'Task: ', read its text with std::getline (so tasks can contain spaces), and tasks.push_back(t). Listing loops with an index and prints i + 1 — humans count from 1 even though the vector counts from 0 — plus '[x]' or '[ ]' from the done flag.
Step 4: Complete and delete by number — carefully
Both operations read a number n, check 1 <= n <= tasks.size(), then act on tasks[n - 1]. The -1 conversion between human numbering and vector indexing is where every beginner bug in this project lives. Deleting uses tasks.erase(tasks.begin() + (n - 1)), which shifts everything after it down one place.
Step 5: Add save and load so the list survives
The starter menu works in memory; the checklist wants persistence. Save with std::ofstream: write each task as one line, done flag first ('1 Buy milk'). Load at startup with std::ifstream and std::getline, splitting the flag from the text. Save after EVERY change, not just on quit — then even a crash loses nothing.
Step 6: Test the full lifecycle
Add three tasks, list them, complete number 2, delete number 1, list again and confirm the numbering shifted correctly. Quit, relaunch, and confirm the list reloads exactly as you left it. That restart test is the one that proves the file code works.
Common mistakes
- Forgetting std::cin.ignore() after reading the menu choice, so 'Add' instantly stores an empty task from the leftover newline.
- Mixing the user's 1-based numbers with the vector's 0-based indexes — completing task 1 marks the SECOND task.
- Saving only when the user picks Quit, so killing the program loses the whole list.
Compile and run
g++ -std=c++17 -o todo todo.cppSample run
$ ./todo
1) Add 2) List 3) Complete 4) Delete 0) Quit
> 1
Task:
> Buy milk and eggs
1) Add 2) List 3) Complete 4) Delete 0) Quit
> 1
Task:
> Finish C++ project lecture notes
> 2
1. [ ] Buy milk and eggs
2. [ ] Finish C++ project lecture notes
> 3
Task number:
> 2
1. [x] Buy milk and eggs
2. [ ] Finish C++ project lecture notes
> 0Try it in your browser
No browser demo is included for this project. Build the C++ version below — that is the real program.