renvoyer const char * en char * puis changer les données

Je suis confus sur le code suivant:

ssortingng _str = "SDFDFSD"; char* pStr = (char*)_str.data(); for (int i = 0; i < iSize; i++) pStr[i] = ::tolower(pStr[i]); 

Ici, _str.data() renvoie const char* . Mais nous l’atsortingbuons à un caractère char* . Mes questions sont,

_str.data() renvoie un pointeur sur une donnée constante. Comment est-il possible de le stocker dans un pointeur sur des données? Les données étaient constantes non? Si nous l’atsortingbuons à un pointeur de caractères, nous pourrons le changer comme nous le faisons dans l’instruction for, ce qui ne devrait pas être possible pour des données constantes.

Ce que vous faites n’est pas valide au niveau de la bibliothèque standard (vous ne respectez pas le std::ssortingng contract ), mais valide au niveau du langage principal C ++.

Le caractère char * renvoyé par les data ne doit pas être écrit, car il pourrait par exemple être en théorie (*) partagé entre différentes chaînes ayant la même valeur.

Si vous voulez modifier une chaîne, utilisez simplement std::ssortingng::operator[] qui informera l’object de l’intention et se chargera de créer un tampon privé pour l’instance spécifique au cas où la chaîne aurait été partagée à la place.

Techniquement, vous êtes autorisé à rejeter la constance d’un pointeur ou d’une référence, mais si l’opération est valide ou non, cela dépend de la sémantique du cas spécifique. La raison pour laquelle l’opération est autorisée est que la philosophie principale du C ++ est que les programmeurs ne font aucune erreur et savent ce qu’ils font. Par exemple, il est techniquement légal, du sharepoint vue du langage C ++, de faire memcpy(&x, "hello", 5)x est une instance de classe, mais les résultats sont très probablement un “comportement non défini”.

Si vous pensez que votre code “fonctionne”, c’est parce que vous avez une mauvaise compréhension de ce que “fonctionne” devrait réellement vouloir dire (indice: “fonctionne” ne signifie pas qu’une fois le code a été observé, il semble que ce qui est raisonnable, mais cela fonctionnera dans tous les cas). Une implémentation C ++ valide est libre de faire ce que vous voulez si vous exécutez ce programme: le fait d’observer quelque chose qui vous semble correct ne veut pas dire grand chose, peut-être n’avez-vous pas semblé assez près ou avez-vous eu de la chance ( malheureux, en fait) qu’aucun accident ne s’est produit tout de suite.

(*) De nos jours, les implémentations de std :: ssortingng avec COW (copie sur écriture) ont une faible popularité car elles posent beaucoup de problèmes (par exemple avec le multithreading) et la mémoire coûte beaucoup moins cher maintenant. Toujours std::ssortingng contract dit que vous n’êtes pas autorisé à changer la mémoire indiquée par la valeur de retour de data() ; si vous faites quelque chose peut arriver.

Ne fais pas ça. Dans ce cas, cela peut aller, mais comme le dit la documentation de data() :

Le pointeur renvoyé peut être invalidé par des appels ultérieurs à d’autres fonctions membres modifiant l’object.

Un programme ne doit modifier aucun des caractères de cette séquence.

Donc, vous pourriez très accidentellement écrire dans une mémoire invalide si vous gardiez ce pointeur autour de vous. Ou, en fait, ruiner l’implémentation de std :: ssortingng. J’irais presque jusqu’à dire que cette fonction ne devrait pas être exposée.

std :: ssortingng offre un operator[] non-const operator[] à cette fin.

 ssortingng _str = "SDFDFSD"; for (int i = 0; i < iSize; i++) _str[i] = ::tolower(_str[i]); 

Vous ne devez jamais changer les données renvoyées directement par std::ssortingng::data() ou std::ssortingng::c_str() .

Pour créer une copie d’un std::ssortingng :

 std::ssortingng str1 = "test"; std::ssortingng str2 = str1; // copy. 

Changer les caractères dans une chaîne:

 std::ssortingng str1 = "test" str1[0] = 'T'; 

La méthode “correcte” consisterait à utiliser std::transform place:

 std::transform(_str.begin(), _str.end(), _str.begin(), ::tolower); 

La réponse simple à votre question est qu’en C ++, vous pouvez rejeter le «const» d’une variable.

Vous ne devriez probablement pas si.

Voir ceci pour la correction de const en C ++

Ssortingng alloue toujours de la mémoire sur le tas, il ne s’agit donc pas de données const, mais simplement d’une marque (dans la signature method data ()) afin d’empêcher toute modification.

Mais rien n’est impossible en C ++. Ainsi, avec un cast simple, bien que dangereux, vous pouvez maintenant traiter le même espace mémoire comme modifiable.

Toutes les constantes d’un programme C / C ++ (comme "SDFDFSD" ci-dessous) seront stockées dans une section séparée .rodata . Cette section est mappée en lecture seule lorsque le fichier binary est chargé en mémoire lors de l’exécution.

 int main() { char* ptr = "SDFDFSD"; ptr[0]='x'; //segmentation fault!! return 0; } 

Par conséquent, toute tentative de modification des données à cet emplacement entraînera une erreur d’exécution, c’est-à-dire une erreur de segmentation .


Pour répondre à la question ci-dessus, lors de la création d’une chaîne de caractères et de l’affectation d’une chaîne à celle-ci, une nouvelle copie en mémoire existe maintenant (la mémoire est utilisée pour contenir les propriétés de l’object chaîne _str ). C’est sur le tas et PAS mappé à une section en lecture seule. La fonction membre _str.data() pointe vers l’emplacement en mémoire qui est mappé en lecture / écriture.

Le qualificatif const du type de retour garantit que cette fonction n’est PAS transmise accidentellement à des fonctions de manipulation de chaîne qui attendent un pointeur char* non-const.

Dans votre itération actuelle, il n’y avait aucune limitation sur l’emplacement de mémoire lui-même qui contenait les données de l’object chaîne; c’est-à-dire qu’il a été mappé avec les deux permissions de lecture / écriture. Par conséquent, la modification de l’emplacement à l’aide d’un autre pointeur non-const, c’est-à-dire que pStr[i] à gauche d’une affectation NE résultait PAS en une erreur d’exécution, car il n’y avait pas de ressortingctions inhérentes à l’emplacement de mémoire lui-même.

Là encore, il n’est PAS garanti que cela fonctionne et qu’un comportement spécifique à l’implémentation que vous avez observé (c’est-à-dire que cela fonctionne tout simplement pour vous) et ne peut pas toujours en dépendre.