2010-03-09 5 views
10

Y at-il des options g ++ qui peuvent détecter une initialisation incorrecte de std :: string avec NULL const char *?Eviter une mauvaise initialisation de std :: string avec NULL const char * en utilisant g ++

J'étais en train de transformer certains champs int en std :: ones chaîne, à savoir:

struct Foo 
{ 
    int id; 
    Foo() : id(0) {} 
}; 

... transformé en:

struct Foo 
{ 
    std::string id; 
    Foo() : id(0) {} //oooops! 
}; 

Je complètement oublié mauvais 'id' l'initialisation avec 0 et g ++ ne m'a donné aucun avertissement du tout. Cette erreur a été détectée dans le temps d'exécution (le constructeur std :: string a jeté une exception) mais j'aimerais vraiment détecter de telles choses au moment de la compilation. Y a-t-il un moyen?

+2

Malheureusement, 0 est la valeur qui ne déclenchera pas une erreur pour une conversion invalide de int en pointeur. Car bien sûr, 0 est une constante de pointeur nulle, elle est donc convertible en n'importe quel type de pointeur. Je ne sais rien de ce que vous pouvez faire d'autre que, comme le dit le visiteur, ne pas écrire cet initialiseur en premier lieu. –

+0

La solution appropriée aurait été d'ajouter un constructeur privé 'std :: string :: string (int); Ce serait une meilleure correspondance, et donc provoquer une erreur de compilation. – MSalters

+1

Je ne sais pas si vous l'aviez voulu de cette façon, mais cela pourrait effectivement fonctionner, comme un test ponctuel pour détecter les erreurs résultant de cette série de changements de 'int' à' string'. Modifiez 'std :: basic_string' dans les en-têtes standard de g ++, vérifiez que le nouveau code compile, puis modifiez-le rapidement, avant que quelqu'un s'en aperçoive. –

Répondre

5

Je pense que c'est en fait un comportement non défini et non vérifié par le compilateur. Vous avez de la chance que cette implémentation génère une exception.

Cependant, vous pouvez éviter ces problèmes en spécifiant que vous souhaitez par défaut ou zéro l'initialisation d'une manière de type agnostique:

struct Foo 
{ 
    X id; 
    Foo() : id() {} //note empty parenthesis 
}; 
+0

Hm ... donc vous dites que le constructeur par défaut pour le type int affecte 0? – pachanga

+3

Cette syntaxe signifie une initialisation zéro pour les types intégrés. – visitor

+0

Merci pour l'info! – pachanga

2

Il y a infrastructure GCC pour produire exactement ce genre d'avertissement:

void foo(const char* cstr) __attribute__((nonnull (1))); 

void bar() { 
    foo(0); 
} 

lorsqu'il est compilé avec -Wnonnull (qui est impliqué par -Wall) produit:

warning: null argument where non-null required (argument 1) 

En principe, vous devriez être en mesure de modifier l'en-tête du système concerné (ou, mieux pour expérimenter, modifier votre propre $ HOME/bits/basic_string.h copier puis le système un outrepasser avec -isystem $HOME) similaire:

basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()) 
    __attribute__((nonnull (1))); 

Cependant, cela n'aide pas car (au moins dans 4.0.1) -Wnonnull n'est pas supporté en C++ et l'attribut est apparemment ignoré. Ce n'est pas évident pourquoi c'est ainsi; Peut-être que l'on pensait qu'il interagissait mal avec la surcharge ou quelque chose.

+1

En fait votre 'base_string' ctor' __attribute __ ((nonnull (1))) 'ci-dessus vérifie que le pointeur' this' n'est pas 'NULL'; passez simplement à '__attribute __ ((nonnull (2)))' pour vérifier que '__s' est non nul; voir http://gcc.gnu.org/ml/gcc/2006-04/msg00549.html – vladr

7

Je ne peux pas penser à un moyen de détecter ce à la compilation, j'ai donc écrit une fonction constructeur de chaîne qui traite correctement avec des pointeurs nuls:

// FUNCTION :  safe_string(char const* pszS) 
// PARAMATERS : pszS  source string to build a string from (may be NULL or 0-length) 
// DESCRIPTION : Safely builds a string object from a char*, even a NULL pointer 
// RETURNS :  string 

template<class C> 
inline basic_string<C> safe_string(const C* input) 
{ 
    if(!input) 
     return basic_string<C>(); 
    return basic_string<C>(input); 
} 

J'utilise cette chaque fois que je crée une chaîne et il y a une chance que l'entrée soit NULL.

Questions connexes