C++ SSO : How to programatically find if a std::wstring is allocated with Short String Optimization?

Viewed 226

How to programatically find if a std::wstring is allocated with Short String Optimization? I was trying to detect such cases and use reserve to move out of the SSO.

The below code prints a small difference in the addresses:

#include <string>
#include <iostream>
int main () 
{
    std::wstring str = L"H";
    std::cout<<&str<<" "<<(void*)str.data()<<"\n";
} 

Output example:

0x7ffc39465220 0x7ffc39465230

enter image description here

Although in windows console app the address comes exactly same:

enter image description here

2 Answers

There are two main ways to go about it:

  1. Just straight-up test it.

    Remember to use std::less to get a full order, and std::addressof to account for overloaded op& in weird classes.

    template <class T>
    constexpr bool uses_sbo(T&& t) noexcept {
        auto less = std::less<const volatile void*>();
        auto p = std::addressof(t);
        return less(t.data(), p + 1) && !less(p, t.data()));
    }
    
    
  2. Compare the capacity.

    This relies on the implementation being sensible, meaning never allocating dynamically when the current capacity suffices.

    template <class T>
    constexpr bool is_minimal(T&& t) noexcept {
        return t.capacity() == T().capacity();
    }
    
    

Both were generalized for all contiguous containers.

template<typename T>
bool ssoTest1(const std::basic_string<T>& s)
{
    return s.capacity() == std::basic_string<T>{}.capacity();
}

template<typename T>
bool ssoTest2(const std::basic_string<T>& s)
{
    uintptr_t r = s.data() - reinterpret_cast<const T*>(&s);
    return r <= sizeof(s);
}

https://godbolt.org/z/v3b57Y

Related