C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
65: Sets and Multisets
By the time you get to sets, you've probably spent a lot of time with vectors. Most of the time, vectors are exactly what you need. But there are specific scenarios where managing a list manually—sorting it, checking for duplicates—becomes a nightmare. That's where std::set and std::multiset come in.
Wait, why not just use a sorted vector?
I get this question a lot. If you just need a sorted list of unique items, you could technically use a std::vector, call std::sort, and then use std::unique. But that's a "snapshot" approach. If you're constantly adding new elements, you'd have to re-sort the whole thing every single time, which is incredibly inefficient.
A std::set is different. It's usually implemented as a red-black tree. This means the moment you insert an element, the set finds its correct sorted position. It also automatically rejects duplicates. If you try to insert "Apple" into a set that already contains "Apple", the set just says "no thanks" and does nothing.
#include <iostream> #include <set> #include <string> int main() { std::set<std::string> inventory; inventory.insert("Health Potion"); inventory.insert("Iron Sword"); inventory.insert("Health Potion"); // Duplicate! This will be ignored. for (const auto& item : inventory) { std::cout < item < " "; } // Output: Health Potion Iron Sword (alphabetically sorted) return 0; }I need duplicates, but I still want them sorted. Is that possible?
Yes, and that's exactly why
std::multisetexists. It's identical tostd::setin terms of performance and ordering, but it doesn't care about uniqueness. I find this incredibly useful for things like combat logs or price trackers where the same value can appear multiple times, but you still want to be able to find the "cheapest" or "most expensive" item quickly.One thing to watch out for: when you call
.erase(value)on a multiset, it removes all instances of that value. If you only want to remove one instance of a duplicate, you have to pass an iterator to the specific element you want to kill.#include <iostream> #include <set> int main() { std::multiset<int> damage_values = {10, 50, 20, 50, 30}; // We have two 50s. Let's remove just one. auto it = damage_values.find(50); if (it != damage_values.end()) { damage_values.erase(it); // Only removes the one pointed to by 'it' } for (int val : damage_values) { std::cout < val < " "; } // Output: 10 20 30 50 return 0; }Can I just modify a value while it's inside a set?
Short answer: No. Long answer: Absolutely not.
Think about why. The set is ordered. If you could reach inside a set and change a
10to a1000, that element would now be in the wrong place, and the internal tree structure would be corrupted. The set would effectively "break."Because of this, elements in a set are treated as
const. If you need to change a value, the pattern is: erase the old value, modify it, then insert the new value. It feels clunky, but it's the only way to guarantee the set stays sorted. (In C++17, we got.extract(), which lets you "pluck" a node out of the tree, change the value, and put it back, but the erase/insert pattern is still the standard way most people handle this).How do I check if something exists without adding it?
You don't want to use
.insert()just to see if something is there, because that modifies the container. Instead, use.find(). It returns an iterator to the element if it exists, orset.end()if it doesn't. For a quick true/false check,.count()is also handy; in a regularstd::set, it will only ever return 0 or 1.if (inventory.find("Magic Wand") != inventory.end()) { std::cout < "You already have the wand!"; }
📋 Practical Task
Exercise: Game Loot Rarity Tracker
You are building a loot system for an RPG. You need to track two things: exactly which unique types of items a player has discovered, and a complete list of every single item dropped (including duplicates) to calculate total loot value.
Write a program that does the following:
- Creates a
std::setcalleddiscoveredItemsto store unique item names. - Creates a
std::multisetcalledlootPileto store the gold value of every item dropped. - Simulates the following drops:
- "Iron Sword" (Value: 15)
- "Health Potion" (Value: 5)
- "Iron Sword" (Value: 15)
- "Magic Shield" (Value: 50)
- "Health Potion" (Value: 5)
- Prints the list of unique items discovered (they should appear in alphabetical order).
- Prints the total number of items in the loot pile.
- Prints the value of the most expensive item in the loot pile (Hint: the last element of a sorted set is the largest).
There are no comments for now.