2010-12-02 3 views
1

Classe:const char * dans ma classe a du caractère indésirable (s) après elle est renvoyée de la fonction

class myclass { 
    public: 
    myclass(void); 

    const char* server; 

    private: 
    char pidchar[6]; 
    int pidnum; 

}; 

La fonction

myclass parseINI(const char* file) 
{ 
    myclass iniOptions; 
    CSimpleIniA ini; 
    ini.SetUnicode(); 
    ini.LoadFile(file); 
    const char* server = ini.GetValue("", "server", ""); 
    iniOptions.server = server; 
    std::cout << server << "\n"; // Prints the correct value here 
    fflush(stdout); 
    return iniOptions; 


} 

Qualifiant de la fonction principale

int _tmain(int argc, TCHAR* argv[]) 
{ 

myclass options; 
options = parseINI("myapp.ini"); 
std::cout << options.server << "\n"; // It prints junk here 
return 0; 
} 

Qu'est-ce que j'ai fait de mal? IniOptions est situé sur la pile et est éliminé automatiquement au retour de la fonction.

Répondre

5

Le const char* retourné par GetValue() probablement appartenu à l'objet ini. Lorsque vous avez quitté la fonction parseIni(), ini est sorti de la portée et a été détruit, ce qui peut signifier que votre pointeur n'est plus valide.

Essayez d'utiliser un std::string pour le type de membre server au lieu de const char*.

+0

Si 'CSimpleINIA' est modifiable, c'est nettement mieux. –

+0

La modification suggérée est 'myclass', pas' CSimpleIniA'. – aschepler

+0

+1 pour suggérer l'utilisation de std :: string qui va créer une copie locale. – Matt

0

Vous devez l'allouer en tas à l'aide de new()

+0

dieu Cher, ne pas oublier de tenter une suppression en le déconstructeur, cependant. – Squirrelsama

+1

Cela ne devrait pas importer, en raison de RVO. Le problème est l'utilisation d'une autre mémoire allouée par pile via 'ini'. http://stackoverflow.com/questions/1394229/understanding-return-value-optimization-and-returning-temporaries-c –

+0

Même sans RVO, cela ne causera pas de problème (sauf si une classe a un constructeur de mauvaise copie, qui est pas le cas cette fois). Il n'y a pas de bonne raison de ne pas renvoyer un objet de classe par valeur. – aschepler

2

Il semble que vous utilisiez la mémoire qui est libérée lorsque CSimpleIniA est hors de portée dans parseINI.

const char* server = ini.GetValue("", "server", ""); 
iniOptions.server = server; 

Copie la valeur qui est renvoyée dans un nouveau bloc de mémoire avant de revenir de la fonction parseINI.

string server = ini.GetValue("", "server", ""); 
iniOptions.server = new char[server.length() + 1]; 
std::copy(server.begin(), server.end(), iniOptions.server);   
iniOptions.server[server.length()] = 0; 
+0

Je ne suis pas sûr de savoir comment le code ci-dessus aide? –

+0

@Martin - juste en soulignant où l'erreur était alors que j'ai essayé l'alternative. –

+0

Comment je fais ça? – codefrog

1
const char* server = ini.GetValue("", "server", ""); 

Cette valeur tombe hors de portée lorsque la fonction se termine, de sorte que lorsque vous attribuez la valeur de ce pointeur sur le pointeur de serveur de votre objet, la place en mémoire ils pointent est d'avoir la mémoire libérée de la pile à la fin de la fonction, et il est alors dépassé par d'autres choses. L'utilisation d'une chaîne std :: string ou même simplement d'un char [] sera préférable pour régler le problème avec le moins de changements, car ils assigneront la valeur réelle et non pas un emplacement dans la mémoire comme des pointeurs.

Ce que vous devriez vraiment faire est de rechercher la transparence référentielle, cependant. Cela empêchera de tels problèmes de se produire à nouveau

1

Je suppose que la durée de vie des données pointées par le char* retourné par CSimpleIniA::GetValue() est la même que l'objet CSimpleIni lui-même. Ainsi, lorsque ini est détruit, le pointeur retourné de GetValue() devient invalide. (Je n'ai jamais utilisé CSimpleIni, et je n'ai pas regardé les docs avec suffisamment d'attention, mais c'est ce que le comportement indique).

Je vous suggère de changer myclass::server d'être un objet std:string et mettez-le en utilisant quelque chose comme:

iniOptions.server = std::string(server); 

qui donnera l'objet myclass::server sa propre copie des données de chaîne.

0

Le problème est que la variable locale server pointe vers un tampon de caractères retourné par ini.GetValue(), qui est détruit lorsque paraseINI() renvoie. Une façon de résoudre ce problème est d'allouer un nouveau tampon et de copier les caractères.

const char* server = ini.GetValue("", "server", ""); 
int length = strlen(server) + 1; // length of the string +1 for the NULL character. 
delete [] iniOptions.server; // free the old buffer 
iniOptions.server = new char[length]; // allocate your own buffer 
strncpy(iniOptions.server, server, length); // copy the characters 

Pour cela fonctionne, vous devez faire myclass::server non-const, et vous devez l'initialiser à NULL dans le constructeur et le supprimer dans le destructor.

Une meilleure façon de gérer cette situation serait d'utiliser std::string au lieu de char * pour muclass::server. De cette façon, std::string prendrait soin de la gestion de la mémoire pour vous, et le code serait exceptionnellement sûr.

Si vous faites un muclass::serverstd::string, vous faites simplement

const char* server = ini.GetValue("", "server", ""); 
iniOptions.server = std::string(server); 

Et vous n'avez rien à faire avec elle dans le constructeur ou l'destructor.

+0

erreur C2664: 'strlen': impossible de convertir le paramètre 1 de 'std :: string' en 'const char *' 1> Aucun opérateur de conversion défini par l'utilisateur disponible qui peut effectuer cette conversion, ou l'opérateur ne peut pas être appelé error C2664: 'strncpy': impossible de convertir le paramètre 1 de 'const char *' en 'char *' 1> La conversion perd les qualificatifs – codefrog

+0

Vous ne devriez pas avoir cette erreur si 'server' est' const char * '. Et si vous en faites un 'std :: string' alors vous n'avez pas besoin de faire votre propre allocation de mémoire, je. e. non 'strlen()' et non 'new'. – Dima

1

La façon dont vous utilisez la classe en tant que fonction renvoyée en C++ est totalement erronée. En C++, il existe 2 types de types de données: type de valeur, type de référence. classe appartient à la deuxième; À partir d'une fonction, vous pouvez renvoyer une donnée de type valeur ou un pointeur de n'importe quelle donnée. Mais vous ne pouvez pas renvoyer une entité d'un type de référence. Car une entité d'un type de référence sera publiée juste après que le code ait atteint la portée de définition de l'entité.

Vous pouvez le faire dans les deux sens:

1: définissent parseINI comme:

 myclass* parseINI(const char* file) 
    {  
      myclass* iniOptions = new myclass(); 
      ........ 
      return iniOptions; 
     } 

puis l'utiliser comme ceci:

 myclass* options = parseINI("myapp.ini"); 

2: définissent parseINI comme:

 void parseINI(myclass& options, const char* file) 
     {  
      ........//asigne value to options's members 
     } 

puis l'utiliser comme ceci:

 myclass options; 
     parseINI(options,"myapp.ini"); 

3: Faites ce que vous avez fait, mais ajouter une méthode asignment (opérateur =) à myClass

Questions connexes