Est-ce que “& s ” pointe vers des caractères contigus dans un std :: ssortingng?

Je fais des travaux de maintenance et j’ai rencontré quelque chose comme:

std::ssortingng s; s.resize( strLength ); // strLength is a size_t with the length of a C ssortingng in it. memcpy( &s[0], str, strLength ); 

Je sais que l’utilisation de & s [0] serait sans danger s’il s’agissait d’un std :: vector, mais s’agit-il d’une utilisation sûre de std :: ssortingng?

Il n’est pas garanti que l’allocation de std :: ssortingng soit contiguë dans la norme C ++ 98/03, mais C ++ 11 la force à l’être. En pratique, ni moi ni Herb Sutter ne connaissons une implémentation qui n’utilise pas de stockage contigu.

Notez que le fonctionnement de &s[0] est toujours garanti par le standard C ++ 11, même dans le cas d’une chaîne de longueur nulle. Cela ne serait pas garanti si vous str.begin() ou &*str.begin() , mais pour &s[0] la norme définit l’ operator[] comme &*str.begin() :

Retourne : *(begin() + pos) si pos < size() , sinon une référence à un object de type T avec la valeur charT() ; la valeur de référence ne doit pas être modifiée

En continuant, data() est défini comme:

Retourne: Un pointeur p tel que p + i == &operator[](i) pour chaque i dans [0,size()] .

(notez les crochets aux deux extrémités de la plage)


Remarque : la pré-normalisation C ++ 0x ne garantissait pas que &s[0] fonctionne avec des chaînes de longueur nulle (en fait, c'était un comportement explicitement non défini), et une révision plus ancienne de cette réponse l'expliquait; cela a été corrigé dans les versions standard ultérieures, la réponse a donc été mise à jour en conséquence.

Il est sécuritaire d’utiliser. Je pense que la plupart des réponses étaient correctes une fois, mais la norme a changé. Citant la norme C ++ 11, exigences générales basic_ssortingng [ssortingng.require] , 21.4.1.5, dit:

Les objects de type caractère dans un object basic_ssortingng doivent être stockés de manière contiguë. Autrement dit, pour tout object basic_ssortingng s, l’identité & * (s.begin () + n) == & * s.begin () + n doit être conservée pour toutes les valeurs de n telles que 0 <= n

Un peu avant cela, il est dit que tous les iterators sont des iterators à access aléatoire. Les deux bits prennent en charge l’utilisation de votre question. (En outre, Stroustrup l’utilise apparemment dans son dernier livre;))

Il n’est pas improbable que ce changement ait été effectué en C ++ 11. Il me semble que je me souviens que la même garantie a été ajoutée pour vector, qui a également reçu le très utile pointeur data () avec cette version.

J’espère que cela pourra aider.

Techniquement, non, car std::ssortingng n’est pas nécessaire pour stocker son contenu de manière contiguë en mémoire.

Cependant, dans presque toutes les implémentations (chaque implémentation dont je suis au courant), le contenu est stocké de manière contiguë et cela “fonctionnerait”.

Les lecteurs doivent noter que cette question a été posée en 2009, alors que la publication actuelle était la norme C ++ 03. Cette réponse est basée sur cette version de Standard, dans laquelle il n’est pas garanti que std::ssortingng s utilise le stockage contigu. Étant donné que cette question n’a pas été posée dans le contexte d’une plate-forme particulière (comme gcc), je ne fais aucune hypothèse à propos de la plate-forme d’OP – en particulier, que la météo soit ou non utilisée, elle utilisait un stockage contigu pour la ssortingng .

Légal? Peut-être peut-être pas. Sûr? Probablement, mais peut-être pas. Bon code? Eh bien, n’allons pas là-bas …

Pourquoi ne pas simplement faire:

 std::ssortingng s = str; 

…ou:

 std::ssortingng s(str); 

…ou:

 std::ssortingng s; std::copy( &str[0], &str[strLen], std::back_inserter(s)); 

…ou:

 std::ssortingng s; s.assign( str, strLen ); 

?

Le code peut fonctionner, mais plus par chance que par jugement, il fait des hypothèses sur la mise en œuvre qui ne sont pas garanties. Je suggère que la détermination de la validité du code soit sans importance alors que c’est une complication inutile qui se réduit facilement à tout simplement:

 std::ssortingng s( str ) ; 

ou si vous atsortingbuez à un object std :: ssortingng existant, simplement:

 s = str ; 

puis laissez std :: ssortingng lui-même déterminer comment atteindre le résultat. Si vous avez recours à ce genre de bêtises, vous pouvez également ne pas utiliser std :: ssortingng et vous en tenir à cela, car vous réintroduisez tous les dangers associés aux chaînes de caractères C.

Cela n’est généralement pas sûr, que la séquence de chaîne interne soit stockée en mémoire en permanence ou non. Il pourrait y avoir beaucoup d’autres détails d’implémentation liés à la façon dont la séquence contrôlée est stockée par l’object std::ssortingng , en plus de la continuité.

Un problème pratique réel avec cela pourrait être le suivant. La séquence contrôlée de std::ssortingng ne doit pas nécessairement être stockée en tant que chaîne terminée par zéro. Cependant, dans la pratique, de nombreuses implémentations (la plupart?) Choisissent de surdimensionner le tampon interne de 1 et stockent la séquence comme une chaîne terminée par zéro, car cela simplifie l’implémentation de la méthode c_str() : il suffit de renvoyer un pointeur sur le tampon interne et vous avez terminé.

Le code que vous avez cité dans votre question ne fait aucun effort pour mettre les données à zéro, il est copié dans la mémoire tampon interne. Très probablement, il ne sait simplement pas si la terminaison zéro est nécessaire pour cette implémentation de std::ssortingng . Il est fort possible que le tampon interne soit rempli de zéros après l’appel du resize . Le caractère supplémentaire atsortingbué au terminateur zéro par l’implémentation est donc préréglé à zéro. Tout ceci est un détail de mise en œuvre, ce qui signifie que cette technique repose sur des hypothèses plutôt fragiles.

En d’autres termes, dans certaines implémentations, vous devrez probablement utiliser strcpy , pas memcpy pour forcer les données dans la séquence contrôlée comme ça. Alors que dans d’autres implémentations, vous devriez utiliser memcpy et non strcpy .