guidelines - modern c++ best practices




Signification de l'acronyme SSO dans le contexte de std:: string (2)

Contexte / Aperçu

Les opérations sur les variables automatiques ("from the stack", qui sont des variables que vous créez sans appeler malloc / new ) sont généralement beaucoup plus rapides que celles impliquant le free store ("the heap", qui sont des variables créées en utilisant new ). Cependant, la taille des tableaux automatiques est fixée au moment de la compilation, mais pas la taille des tableaux du magasin libre. De plus, la taille de la pile est limitée (typiquement quelques MiB), alors que le stockage gratuit n'est limité que par la mémoire de votre système.

SSO est l'optimisation de chaîne courte / petite. Une std::string stocke généralement la chaîne sous la forme d'un pointeur vers le magasin libre ("le tas"), ce qui donne des caractéristiques de performance similaires à celles que vous obtiendriez si vous appeliez un new char [size] . Cela évite un débordement de pile pour les très grandes chaînes, mais il peut être plus lent, en particulier avec les opérations de copie. En tant qu'optimisation, de nombreuses implémentations de std::string créent un petit tableau automatique, quelque chose comme char [20] . Si vous avez une chaîne de 20 caractères ou moins (dans cet exemple, la taille réelle varie), elle le stocke directement dans ce tableau. Cela évite d'avoir à appeler du new , ce qui accélère un peu les choses.

MODIFIER:

Je ne m'attendais pas à ce que cette réponse soit aussi populaire, mais puisque c'est le cas, laissez-moi vous donner une implémentation plus réaliste, avec la mise en garde que je n'ai jamais lu aucune implémentation de SSO "dans la nature".

Détails d'implémentation

Au minimum, une std::string doit stocker les informations suivantes:

  • La taille
  • La capacité
  • L'emplacement des données

La taille peut être stockée en tant que std::string::size_type ou en tant que pointeur vers la fin. La seule différence est de savoir si vous voulez soustraire deux pointeurs lorsque l'utilisateur appelle la size ou ajouter un size_type à un pointeur lorsque l'utilisateur appelle end . La capacité peut être stockée dans les deux sens.

Vous ne payez pas pour ce que vous n'utilisez pas.

D'abord, considérons l'implémentation naïve basée sur ce que j'ai décrit ci-dessus:

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;
};

Pour un système 64 bits, cela signifie généralement que std::string a 24 octets de 'overhead' par chaîne, plus 16 autres pour le tampon SSO (16 choisi ici au lieu de 20 en raison des exigences de remplissage). Il ne serait pas vraiment logique de stocker ces trois membres de données plus un tableau local de caractères, comme dans mon exemple simplifié. Si m_size <= 16 , alors je mettrai toutes les données dans m_sso , donc je connais déjà la capacité et je n'ai pas besoin du pointeur vers les données. Si m_size > 16 , alors je n'ai pas besoin de m_sso . Il n'y a absolument aucun chevauchement où j'ai besoin de tous. Une solution plus intelligente qui ne gaspille pas d'espace ressemblerait à quelque chose d'un peu plus (non testé, à titre d'exemple seulement):

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;
    };
};

Je suppose que la plupart des implémentations ressemblent plus à ceci.

Dans une question C ++ sur l'optimisation et le style de code , plusieurs réponses se référaient à "SSO" dans le contexte de l'optimisation des copies de std::string . Que signifie SSO dans ce contexte?

Clairement pas "single sign on". "Optimisation de chaîne partagée", peut-être?


SSO est l'abréviation de "Small String Optimization", une technique dans laquelle les petites chaînes sont intégrées dans le corps de la classe de chaînes plutôt que d'utiliser un tampon attribué séparément.





optimization