Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

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::multiset exists. It's identical to std::set in 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 10 to a 1000, 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, or set.end() if it doesn't. For a quick true/false check, .count() is also handy; in a regular std::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::set called discoveredItems to store unique item names.
  • Creates a std::multiset called lootPile to 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).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.