DEV Community

C++ Standard Library Hidden Gems - 6 Headers You're Probably Overlooking

<numeric> - Not Just Math, Actually Useful

Most beginners never include <numeric>. I didn't either - until I needed to compute a cumulative sum and wrote a 5-line loop. Then someone showed me:

#include <numeric>
#include <vector>

std::vector<int> v = {1, 2, 3, 4, 5};

// Sum all elements - no loop needed
int total = std::accumulate(v.begin(), v.end(), 0); // 15

// Fill with sequential values
std::iota(v.begin(), v.end(), 1); // v = {1, 2, 3, 4, 5} again

// GCD and LCM (C++17)
int g = std::gcd(12, 18); // 6
int l = std::lcm(12, 18); // 36

// Prefix sum - partial_sum produces {1, 3, 6, 10, 15}
std::vector<int> prefix(v.size());
std::partial_sum(v.begin(), v.end(), prefix.begin());

std::accumulate alone has probably saved me 50 lines of boilerplate. std::gcd and std::lcm replaced hand-written Euclidean algorithm functions I had copy-pasted across three projects.

<algorithm> - Beyond sort(), There's Gold

Everyone knows std::sort. But <algorithm> is massive, and some of its best tools are rarely taught:

#include <algorithm>
#include <vector>

std::vector<int> v = {5, 2, 9, 1, 5, 6};

// Find the 3rd smallest element (no full sort needed!)
std::nth_element(v.begin(), v.begin() + 2, v.end());
// v[2] is now the 3rd smallest; elements before are <=, after are >=

// All permutations (great for brute-force problems on Luogu!)
std::string s = "123";
do {
    std::cout << s << std::endl; // prints 123, 132, 213, 231, 312, 321
} while (std::next_permutation(s.begin(), s.end()));

// Binary search on sorted ranges
bool found = std::binary_search(v.begin(), v.end(), 5);

// Rotate array elements
std::rotate(v.begin(), v.begin() + 2, v.end());
// {1, 2, 3, 4, 5} -> {3, 4, 5, 1, 2}

std::next_permutation is a cheat code for competitive programming brute-force problems. std::nth_element is O(n) - way faster than sorting the whole array when you only need one element.

<string_view> (C++17) - Avoid Unnecessary Copies

When you pass a string to a function, C++ usually copies it (or you use const std::string& and hope the caller has a std::string). What if the caller has a const char* or a substring?

#include <string_view>
#include <iostream>

// Works with std::string, const char*, and substrings - zero copies!
void print_first_word(std::string_view text) {
    auto pos = text.find(' ');
    std::cout << text.substr(0, pos) << std::endl;
}

int main() {
    std::string s = "hello world";
    print_first_word(s);                    // works
    print_first_word("goodbye world");      // works - no allocation!
    print_first_word(s.substr(0, 5) + "!"); // works on substring
}

std::string_view is a lightweight, non-owning view into a string. It's essentially a pointer + length. No heap allocation, no copying. For read-only string parameters, there's almost no reason to use const std::string& anymore.

<optional> (C++17) - Functions That Might Fail, Without Exceptions

How do you write a function that "might not have an answer"? Without <optional>, beginners often return sentinel values like -1 or empty strings:

#include <optional>
#include <string>
#include <vector>

// Clean: no sentinel values, no exceptions
std::optional<int> find_index(const std::vector<int>& v, int target) {
    for (size_t i = 0; i < v.size(); i++) {
        if (v[i] == target) return i;
    }
    return std::nullopt; // "no answer"
}

// Usage
auto idx = find_index({3, 1, 4, 1, 5}, 4);
if (idx) {
    std::cout << "Found at: " << *idx << std::endl; // 2
} else {
    std::cout << "Not found" << std::endl;
}

// Or use value_or() for defaults
int position = find_index({3, 1, 4, 1, 5}, 99).value_or(-1); // -1

This replaces the "is this return value valid?" guessing game with a type-safe approach. The compiler forces you to check before using the value.

<bitset> - Bit Manipulation Without Headaches

Bit operations are common in competitive programming (set representation, DP state compression, flags). The manual way with <<, >>, &, | is error-prone:

#include <bitset>
#include <iostream>

// Fixed-size bit array - operations read like English
std::bitset<8> bits("10110011");

std::cout << bits.count() << std::endl;     // 5 (number of 1s)
std::cout << bits.test(3) << std::endl;     // 0 (bit at position 3)
std::cout << bits.any() << std::endl;       // true (at least one 1?)

bits.set(0, true);   // set bit 0 to 1
bits.flip(2);        // toggle bit 2
bits.reset(7);       // set bit 7 to 0

std::cout << bits.to_ullong() << std::endl;  // convert to unsigned long long
std::cout << bits.to_string() << std::endl;  // back to string "00110011"

std::bitset handles boundary checks and conversion, and the .count() method is internally optimized. For bit DP problems on Luogu, this is a lifesaver.

<tuple> + Structured Bindings (C++17) - Return Multiple Values Cleanly

Returning multiple values from a function used to mean either std::pair (only two values) or std::tuple with verbose std::get<>():

#include <tuple>
#include <iostream>

// Return three values naturally
std::tuple<int, double, std::string> get_stats() {
    return {42, 3.14, "hello"};
}

int main() {
    // C++17 structured binding - auto unpacking!
    auto [count, pi, message] = get_stats();
    std::cout << count << ", " << pi << ", " << message << std::endl;
    // 42, 3.14, hello

    // std::tie for existing variables (works in C++11)
    int a;
    double b;
    std::string c;
    std::tie(a, b, c) = get_stats();
}

Structured bindings work with structs, pairs, tuples, and arrays. Combined with std::map::insert (which returns pair<iterator, bool>), this pattern appears everywhere in modern C++.

Quick Reference

Header Must-Try
<numeric> accumulate, gcd, iota, partial_sum
<algorithm> next_permutation, nth_element, rotate, binary_search
<string_view> Non-owning string parameter - zero-copy
<optional> value_or(), has_value(), std::nullopt
<bitset> count(), set(), flip(), to_string()
<tuple> Structured bindings: auto [a, b, c] = ...

None of these are "advanced." They're just standard tools that most tutorials skip over because they'd rather teach you to write a swap function by hand. Next time you find yourself writing a loop for something that feels like it should be built-in - it probably is.

GitHub: https://github.com/Cn-Alanwu

Tags: #cpp #beginners #tutorial #programming #cpp17 #stl

Comments

No comments yet. Start the discussion.