Je suis nouveau en C ++ et j'expérimentais un peu certaines de ses fonctionnalités (principalement les modèles, les pointeurs, la POO) en essayant de créer une classe de chaînes, lorsque je suis resté coincé dans ce problème. Le code incriminé ressemble à ceci:

String.h

...
private:
        char* value;
...
public:
        string();
...

String.cpp

string::string() : value( '\0' ) {
    std::cout << "Initialized string value: " << this->value << "blablabla" << std::endl;
}

Ce que je pensais arriver, c'est que le memeber de la classe "value" a été initialisé en tant que chaîne vide dès que le constructeur a été appelé, mais apparemment j'avais tort, car quand je l'appelle, je vois ceci sur la console:

"Initialized string value: "

Maintenant, pourquoi la sortie est-elle un peu tronquée une fois qu'elle imprime le membre de classe "valeur"? Qu'est-ce que je fais mal?

c++
0
Federico Luzzi 20 avril 2017 à 21:25

3 réponses

Meilleure réponse

Votre code

string::string() : value( '\0' )

Assigne une valeur entière de 0, un équivalent d'un nullptr ou simplement NULL, à une variable qui est censée être un pointeur vers le premier caractère de votre chaîne.

Une chose que vous pouvez faire pour que ce code particulier fonctionne est de spécifier une chaîne réelle pour l’initialisation:

string::string() : value( "" ) // note the double-quotes to denote a string

Bien sûr, vous devez également implémenter la bonne gestion de ce tampon char* value;, c'est-à-dire vous assurer d'allouer la chaîne lors de l'attribution de valeurs, de libérer de la mémoire lorsque vous n'en avez plus besoin, etc.

N.B.
En aucun cas je ne préconise de le faire de cette façon! Je ne fournis qu'un exemple qui fonctionnerait pour cet extrait de code court. Si vous deviez utiliser une valeur par défaut, je vous suggère d'avoir une variable membre statique que vous utilisez comme initialiseur de "chaîne vide". De cette façon, au moins, vous pouvez vérifier si votre chaîne est vide lorsque vous devez allouer un tampon ou libérer de la mémoire.

Dans votre fichier .h:

private:
    static char empty[];

Et dans votre fichier .cpp:

char string::empty[] = {'\0'};

string::string() : value(empty) {...}
1
YePhIcK 20 avril 2017 à 19:09

Lorsque vous passez char* à operator<< de std::cout, votre char* sera traité comme une chaîne C, ce qui implique qu'il sera déréférencé.

Dans votre cas spécifique, le pointeur value est initialisé avec '\0' - comme votre compilateur vous a peut-être prévenu, c'est une manière implicite de créer un pointeur nul.

Déréférencer un pointeur nul est un comportement indéfini , ce qui explique la troncature abrupte de votre sortie.

Puisque vous avez besoin que votre pointeur soit déréférencé, vous voulez vous assurer qu'il pointe vers une mémoire valide réelle. Cela nécessitera une bonne gestion de la mémoire de votre classe, et ce sujet ne rentrera certainement pas dans une seule réponse SO.

Pensez à lire quelques didacticiels sur la mémoire dynamique en C ++ pour commencer :)

0
Ap31 20 avril 2017 à 18:55

Vous initialisez votre char* avec une valeur numérique de 0, alias NULL. Passer un pointeur NULL char* à operator<< est un comportement indéfini . C'est pourquoi vous voyez une sortie tronquée - std::cin entre dans un état d'échec et ignore donc les appels operator<< suivants.

Si vous voulez que operator<< réussisse, vous devez modifier l'initialisation de votre pointeur char* vers une adresse mémoire réelle (même si ce n'est qu'un caractère nul), par exemple:

string::string() : value( "\0" )

Ou simplement (le \0 est implicite):

string::string() : value( "" )

L'utilisation de " au lieu de ' définit le littéral comme un tableau const char[] en mémoire statique, et un tableau se désintègre en un pointeur.

Maintenant, passer le char* à operator<< aura un comportement bien défini.

Cependant, si vous voulez que votre char* soit NULL lorsque votre chaîne est vide, vous devez faire attention de ne pas passer le char* à operator<< s'il est NULL, par exemple:

class myString
{
private:
    char* value;
    ...

public:
    myString();
    void print(std::ostream &out) const;
};

std::ostream& operator<<(std::ostream &out, const myString &str);
myString::mySstring() : value( 0 ) {}

void myString::print(std::ostream &out) const
{
    if (value) out << value;
}

std::ostream& operator<<(std::ostream &out, const myString &str)
{
    str.print(out);
    return out;
}
myString s;
std::cout << "Initialized string value: " << s << "blablabla" << std::endl;
1
Remy Lebeau 20 avril 2017 à 19:02