std::basic_string::substr(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::basic_string::substr (3) β€” from the C++ Standard Library, bestie

okay so listen. this is the manpage for std::basic_string::substr, straight out of the C++ Standard Library (cppreference, 2024.06.10 β€” we'll get to the credits at the end, don't worry 🫢). it's the little member function that gives you a piece of your string. a lil slice. a substring, if you will. and honestly? iconic behavior. ✨

🌸 NAME 🌸

std::basic_string::substr β€” yes bestie, that's literally it, that's the name, std::basic_string::substr, we're not doing a dramatic reveal here πŸ’€

✨ SYNOPSIS ✨

okay so here's the whole shape of it, and yes there's a pre-C++23 version and a C++23-and-onwards version, and C++20 made it constexpr, keep up, we're slaying:

basic_string substr( size_type pos = 0, size_type            (until C++23)
count = npos ) const;
(constexpr since C++20)
constexpr basic_string
    substr( size_type pos = 0, size_type count =     (1)     (since C++23)
npos ) const&;
constexpr basic_string substr( size_type pos = 0,        (2) (since C++23)
size_type count = npos ) &&;

so what does it actually do? it returns a substring [pos, pos + count). and here's the part everyone gets wrong πŸ₯² β€” if the substring you're asking for extends past the end of the string, like when count is greater than size() - pos (for example when count == npos), the returned substring is just [pos, size()). it gets clamped. it does not throw. it's very chill about it actually.

and the two numbered ones:

  1. equivalent to return basic_string(*this, pos, count);.
  2. equivalent to return basic_string(std::move(*this), pos, count);.

πŸŽ€ PARAMETERS πŸŽ€

  • pos β€” position of the first character to include. where the slice starts.
  • count β€” length of the substring. how much you're taking.

πŸ¦‹ RETURN VALUE πŸ¦‹

a String containing the substring [pos, pos + count) β€” or [pos, size()) if the clamp kicked in. that's the whole thing. πŸ’–

πŸ’€ EXCEPTIONS πŸ’€

std::out_of_range if pos > size().

like, if you ask for a start position past the end, she will throw hands. that's the one thing she won't forgive.

and β€” this is the good part β€” if an exception is thrown for any reason, these functions have no effect. that's the strong exception safety guarantee, and yes she's proud of it. 🌈

πŸ”₯ COMPLEXITY πŸ”₯

linear in count. so like, the more you take, the more work it is. math. πŸ™ˆ

⭐ NOTES ⭐

okay so here's a genuinely important one, don't skip it: the allocator of the returned string is default-constructed. meaning the new allocator might not be a copy of get_allocator(). so if you customized your allocator and assumed it'd carry over β€” nope. it's a fresh one. main character energy, refuses to share a wardrobe. πŸ‘‘

🌸 EXAMPLE 🌸

the vibe, in code, in full:

// Run this code

#include <iostream>
#include <string>

int main()
{
    std::string a = "0123456789abcdefghij";

    // count is npos, returns [pos, size())
    std::string sub1 = a.substr(10);
    std::cout << sub1 << '\n';

    // both pos and pos + count are within bounds, returns [pos, pos +
count)
    std::string sub2 = a.substr(5, 3);
    std::cout << sub2 << '\n';

    // pos is within bounds, pos + count is not, returns [pos, size())
    std::string sub4 = a.substr(a.size() - 3, 50);
    // this is effectively equivalent to
    // std::string sub4 = a.substr(17, 3);
    // since a.size() == 20, pos == a.size() - 3 == 17, and a.size() -
pos == 3

    std::cout << sub4 << '\n';

    try
    {
        // pos is out of bounds, throws
        std::string sub5 = a.substr(a.size() + 3, 50);
        std::cout << sub5 << '\n';
    }
    catch (const std::out_of_range& ex)
    {
        std::cout << ex.what() << '\n';
    }
}

🧚 Possible output 🧚

abcdefghij
567
hij
basic_string::substr: __pos (which is 23) > this->size() (which is 20)

that last line? that's the out_of_range girlie doing her little speech. __pos (which is 23) > this->size() (which is 20). she's right and she's telling you. 😭


πŸ‘‘ Defect reports πŸ‘‘

so the following behavior-changing defect reports were applied retroactively to previously published C++ standards (yes, retroactively, time travel is real, it's giving butterfly effect):

  1. LWG 847 β€” applied to C++98. behavior as published: there was no exception safety guarantee. correct behavior: added strong exception safety guarantee. 🫢 a glow-up, truly.

🌈 See also 🌈

  • copy β€” copies characters (public member function)
  • size / length β€” returns the number of characters (public member function)
  • find β€” finds the first occurrence of the given substring (public member function)
  • npos β€” special value, the exact meaning depends on the context ([static], public static member constant)
  • substr β€” returns a substring (public member function of std::basic_string_view<CharT,Traits>)

and that's the page!! go forth and slice safely, bestie πŸ«ΆπŸ’œ this has been your cppreference moment, brought to you by http://cppreference.com 🌐 and the date 2024.06.10 πŸ“…, documented under the std::basic_string::substr(3) header because that's just how the manual do. periodt. πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from