Ir para o conteúdo

Última atualização:2026-10-12

Teste de desempenho de SSO de string em C++

Hoje quero fazer duas perguntas a vocês:

1.Há diferença de desempenho no código abaixo?

std::string s1("hello world hel");
std::string s2("hello world helo");

2.Quanto é sizeof(std::string)?

Agora, vamos explorar essas duas perguntas juntos.

Como as respostas dessas duas perguntas são diferentes em g++(libstdc++) e clang(libc++), faremos aqui uma análise separada para cada caso.

1.g++(libstdc++)

Para o código-fonte do g++, tomamos o g++-10 como exemplo; o código detalhado pode ser visto neste endereço do github, e aqui listamos o código mais central.

https://github.com/gcc-mirror/gcc/blob/devel/omp/gcc-10/libstdc%2B%2B-v3/include/bits/basic_string.h#L171

template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string {
  private:
    struct _Alloc_hider : allocator_type {
        pointer _M_p; // The actual data.
    };
      enum { __min_cap = 15 / sizeof(value_type) };
    _Alloc_hider    _M_dataplus;             //  8 bytes
    size_type __size_;                     //  8 bytes

    union {
            _CharT           _M_local_buf[_S_local_capacity + 1]; // 16 bytes 
            size_type        _M_allocated_capacity;                             // 8 bytes
    }; // 16 bytes
}; // 32 bytes

No código acima, a parte de comentários lista em detalhes os bytes ocupados pela string (atenção: aqui o value_type é computado como char, ou seja, sizeof(value_type) = 1).

sizeof(string) = 8 + 8 + 16 = 32.

Sendo 8 bytes de ptr, 8 bytes de size e 16 bytes de union.

Quanto ao desempenho, aqui está implementado o SSO: o buffer local armazena no máximo 15 caracteres; acima de 15 caracteres, a alocação acontece na heap. Escrevi um benchmark para comparar o desempenho.

  • O conteúdo do teste de string curta é: "hello world hel", com 15 caracteres no total.
  • O conteúdo do teste de string longa é: "hello world helo", com 16 caracteres no total.
std::string s1("hello world hel");
std::string s2("hello world helo");

Vê-se que a diferença de desempenho é muito grande: um único caractere faz com que o desempenho de std::string mude tanto!

A essência aqui ainda é o SSO local buffer mencionado antes.

Teste de desempenho: https://quick-bench.com/q/s7pvDB_SwQyDCcZk50odAaYIzMc

gcc short long

2.clang++(libc++)

De forma análoga, tomamos o llvm-14 como exemplo; para ver o código completo, basta acessar o endereço do github abaixo; aqui extraímos o código central.

https://github.com/llvm/llvm-project/blob/release/14.x/libcxx/include/string#L765

template<class _CharT, class _Traits, class _Allocator>
class basic_string {
  private:
    struct __long {
        size_type __cap_;               // 8 bytes
        size_type __size_;              // 8 bytes
        pointer   __data_;              // 8 bytes
    };

        enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
                      (sizeof(__long) - 1)/sizeof(value_type) : 2};

    struct __short {
        union {
            unsigned char __size_;      // 1 bytes
            value_type __lx;            // 1 bytes 
        };                              // 1 bytes
        value_type __data_[__min_cap];  // 23 bytes
    };                                  // 24 bytes

        union __ulx {
            __long __lx;        // 24 bytes
            __short __lxx;  // 24 bytes
        }; // 24 bytes
}

No código acima, a parte de comentários lista em detalhes os bytes ocupados pela string (atenção: aqui o value_type é computado como char, ou seja, sizeof(value_type) = 1).

sizeof(string) = tamanho da union; essa union tem 24 bytes, então o valor é 24.

Já o SSO: o buffer local armazena no máximo 22 caracteres; acima de 22 caracteres, a alocação acontece na heap.

Por isso, quando aplicamos na clang o mesmo código de teste usado na gcc, obtivemos um resultado um pouco diferente, ou seja: o desempenho da string longa e o da string curta praticamente não diferem. O motivo é que os casos de teste da gcc estão todos dentro de 22 caracteres, ou seja, todos são strings curtas.

Teste de desempenho: https://quick-bench.com/q/nmLMqQZ31cmWBbbIFr2nHN2JL1k

llvm short long no

Quando testamos strings realmente longas e curtas, o desempenho passa a mudar de forma clara, com a tendência mantendo-se consistente com a da gcc.

  • O conteúdo do teste de string curta é: "hello world hello worl", com 22 caracteres no total.
  • O conteúdo do teste de string longa é: "hello world hello world", com 23 caracteres no total.

Teste de desempenho: https://quick-bench.com/q/ujtMrtotEi6RrpfMDJ1UcSLFIJE

llvm short long

Tópicos relacionados

Comentários