Ú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?
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.
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.
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

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

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

Tópicos relacionados¶
- Comparação de desempenho: memcpy vs std::copy | C++那些事
- Polimorfismo em C++: funções virtuais, CRTP e variant | C++那些事