c++ - siglas - Significado del acrónimo SSO en el contexto de std:: string
significado de las siglas sso (2)
En una pregunta de C ++ sobre la optimización y el estilo del código , varias respuestas se referían a "SSO" en el contexto de la optimización de copias de std::string
. ¿Qué significa SSO en ese contexto?
Claramente no "inicio de sesión único". "Optimización de cadenas compartidas", tal vez?
Fondo / Descripción general
Las operaciones en variables automáticas ("desde la pila", que son variables que se crean sin llamar a malloc
/ new
) son generalmente mucho más rápidas que las que implican la tienda gratuita ("el montón", que son variables que se crean usando new
). Sin embargo, el tamaño de las matrices automáticas se fija en tiempo de compilación, pero el tamaño de las matrices de la tienda gratuita no lo está. Además, el tamaño de la pila es limitado (normalmente unos pocos MiB), mientras que la tienda gratuita solo está limitada por la memoria de su sistema.
SSO es la optimización de cadenas cortas / pequeñas. Una std::string
normalmente almacena la cadena como un puntero a la tienda gratuita ("the heap"), que proporciona características de rendimiento similares a las de un new char [size]
. Esto evita un desbordamiento de pila para cadenas muy grandes, pero puede ser más lento, especialmente con operaciones de copia. Como una optimización, muchas implementaciones de std::string
crean una pequeña matriz automática, algo así como char [20]
. Si tiene una cadena de 20 caracteres o menos (dado este ejemplo, el tamaño real varía), lo almacena directamente en esa matriz. Esto evita la necesidad de llamar a algo new
, lo que acelera un poco las cosas.
EDITAR:
No esperaba que esta respuesta fuera tan popular, pero dado que lo es, permítanme dar una implementación más realista, con la advertencia de que nunca he leído ninguna implementación de SSO "en la naturaleza".
Detalles de implementacion
Como mínimo, std::string
necesita almacenar la siguiente información:
- El tamaño
- La capacidad
- La ubicación de los datos
El tamaño se puede almacenar como std::string::size_type
o como un puntero al final. La única diferencia es si desea restar dos punteros cuando el usuario llama al size
o agrega un size_type
a un puntero cuando el usuario llama a end
. La capacidad se puede almacenar de cualquier manera también.
No pagas por lo que no usas.
Primero, considere la implementación ingenua basada en lo que describí anteriormente:
class string {
public:
// all 83 member functions
private:
std::unique_ptr<char[]> m_data;
size_type m_size;
size_type m_capacity;
std::array<char, 16> m_sso;
};
Para un sistema de 64 bits, eso generalmente significa que std::string
tiene 24 bytes de ''sobrecarga'' por cadena, más otros 16 para el búfer SSO (16 elegidos aquí en lugar de 20 debido a requisitos de relleno). Realmente no tendría sentido almacenar esos tres miembros de datos más una matriz local de caracteres, como en mi ejemplo simplificado. Si m_size <= 16
, pondré todos los datos en m_sso
, por lo que ya conozco la capacidad y no necesito el puntero a los datos. Si m_size > 16
, entonces no necesito m_sso
. No hay absolutamente ninguna superposición cuando los necesito a todos. Una solución más inteligente que no desperdicie espacio se vería algo más parecido a esto (sin probar, solo con fines de ejemplo):
class string {
public:
// all 83 member functions
private:
size_type m_size;
union {
class {
// This is probably better designed as an array-like class
std::unique_ptr<char[]> m_data;
size_type m_capacity;
} m_large;
std::array<char, sizeof(m_large)> m_small;
};
};
Supongo que la mayoría de las implementaciones se parecen más a esto.
SSO es la abreviatura de "Small String Optimization", una técnica donde las cadenas pequeñas están incrustadas en el cuerpo de la clase de cadena en lugar de usar un buffer asignado por separado.