Question

Je fais quelques travaux d'entretien et couru à travers quelque chose comme ce qui suit:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

Je sais en utilisant & s [0] seraient en sécurité si elle était un std :: vecteur, mais est-ce une utilisation sûre de std :: string?

Était-ce utile?

La solution

est pas garanti l'allocation d'un std :: string pour être contiguës selon la norme 98/03 C ++, mais 11 C ++ oblige à être. Dans la pratique, ni moi, ni Herb Sutter savoir d'une mise en œuvre qui n'utilise pas le stockage contigu.

Notez que la chose &s[0] est toujours garanti pour fonctionner par la norme C ++ 11, même dans le cas de chaîne 0 longueur. Il ne serait pas garantie si vous avez str.begin() ou &*str.begin(), mais pour &s[0] la norme définit operator[] comme:

  

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

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

  

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

(notez les crochets aux deux extrémités de l'intervalle)


Avis : pré-normalisation C ++ 0x ne garantit pas &s[0] à travailler avec des chaînes de longueur nulle (en fait, il était explicitement le comportement non défini), et une version plus ancienne de cette réponse expliqué; cela a été corrigé dans les versions standards plus tard, donc la réponse a été mis à jour en conséquence.

Autres conseils

Techniquement, non, puisque std::string est pas nécessaire de stocker son contenu dans la mémoire jointive.

Cependant, dans presque toutes les mises en œuvre (chaque mise en œuvre dont je suis au courant), les contenus sont stockés et ce jointive « travail ». Serait

Il est sûr à utiliser. Je pense que la plupart des réponses sont correctes une fois, mais la norme a changé. Je cite la norme C ++ 11, basic_string exigences générales [string.require] , 21.4.1.5, dit:

  

Les objets char comme dans un objet basic_string doivent être stockés jointive. C'est, pour tout basic_string   objet s, l'identité et * (s.begin () + n) == & * s.begin () + n doit tenir pour toutes les valeurs de n tel que 0   <= N

Un peu avant cela, il est dit que tous les itérateurs sont itérateurs d'accès aléatoire. Les deux bits prennent en charge l'utilisation de votre question. (De plus, il utilise Stroustrup apparemment dans son dernier livre;))

Il est pas improbable que ce changement a été fait en C ++ 11. Je crois me souvenir que la même garantie a été ajoutée ensuite pour le vecteur, qui a également obtenu les très utiles données () pointeur avec cette version.

L'espoir qui aide.

Les lecteurs devraient noter que cette question lorsque la norme C ++ 03 a été demandé en 2009, la publication actuelle. Cette réponse est basée sur cette version de la norme, dans laquelle sont std::strings pas garantie à utiliser le stockage contigu. Étant donné que cette question n'a pas été posée dans le cadre d'une plate-forme particulière (comme gcc), je ne fais pas des hypothèses sur la plate-forme OP - en particulier, le temps ou non utilisé pour le stockage contigious string

.

juridique? Peut-être peut-être pas. Sûr? Probablement, mais peut-être pas. Bon code? Eh bien, allons-y pas ...

Pourquoi ne pas simplement faire:

std::string s = str;

... ou:

std::string s(str);

... ou:

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

... ou:

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

Le code pourrait fonctionner, mais plus par chance que le jugement, il fait des hypothèses sur la mise en œuvre qui ne sont pas garantis. Je suggère de déterminer la validité du code est hors de propos alors qu'il est inutile sur des complications qui est facilement réduit à seulement:

std::string s( str ) ;

ou si l'affectation à un std :: existante objet chaîne, juste:

s = str ;

et puis laissez-std :: chaîne elle-même déterminer comment obtenir le résultat. Si vous allez recourir à ce genre de non-sens, alors vous pouvez aussi bien ne pas utiliser std :: string et de s'y tenir, puisque vous réintroduisez tous les dangers associés à des chaînes C.

Ceci est généralement pas en toute sécurité, que la séquence de chaîne interne est stockée dans la mémoire continue ou non. Il y a peut-être beaucoup d'autres détails de mise en œuvre liés à la façon dont la séquence contrôlée est stockée par objet std::string, en plus de la continuité.

Un problème pratique réel qui pourrait être le suivant. La séquence contrôlée de std::string n'a pas à être stockées sous forme de chaîne à terminaison nulle. Cependant, dans la pratique, beaucoup (? Plus) implémentations choisissent de surdimensionner la mémoire tampon interne par 1 et stocker la séquence en tout cas chaîne terminée par zéro, car il simplifie la mise en œuvre de la méthode de c_str(): il suffit de retourner un pointeur vers la mémoire tampon interne et vous êtes terminé.

Le code que vous avez cité dans votre question ne fait aucun effort pour mettre fin à zéro les données sont copiées dans la mémoire tampon interne. Très probablement, il ne sait tout simplement pas si zéro résiliation est nécessaire pour cette mise en œuvre de std::string. Très probablement, il repose sur la mémoire tampon interne étant rempli de zéros après l'appel à resize, de sorte que le caractère supplémentaire alloué à la terminaison zéro par la mise en œuvre est commodément pré-mise à zéro. Tout cela est un détail de mise en œuvre, ce qui signifie que cette technique dépend de certaines hypothèses plutôt fragiles.

En d'autres termes, dans certaines implémentations, vous auriez 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 que vous auriez à utiliser memcpy et non strcpy.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top