2010-03-09 7 views
10

A czy istnieją opcje g ++, które mogą wykryć niepoprawną inicjalizację std :: string z NULL const char *?Unikanie niepoprawnej inicjalizacji std :: string z NULL const char * przy użyciu g ++

byłem w procesie toczenia kilka pól do int te std :: string, tj

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

... zamienił się:

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

ja całkowicie pomijane złe 'id' inicjalizacja z 0 i g ++ nie dała mi żadnych ostrzeżeń. Ten błąd został wykryty w czasie wykonywania (konstruktor std :: string zgłosił wyjątek), ale naprawdę chciałbym wykryć takie rzeczy w czasie kompilacji. Czy jest jakiś sposób?

+2

Niestety, 0 jest jedyną wartością, która nie spowoduje błędu przy nieprawidłowej konwersji z int na wskaźnik. Ponieważ 0 jest zerową stałą wskaźnika, więc można ją zamienić na dowolny typ wskaźnika. Nie wiem, co możesz zrobić poza tym, że, jak mówi użytkownik, nie pisz tego inicjatora. –

+0

Właściwym rozwiązaniem byłoby dodanie prywatnego konstruktora 'std :: string :: string (int);'. Byłoby to lepsze dopasowanie, a zatem spowodować błąd podczas kompilacji. – MSalters

+1

Nie jestem pewien, czy chodziło ci o to w ten sposób, ale to może zadziałać, jako jednorazowy test, aby wykryć błędy wynikające z tej rundy zmian z 'int' na' string'. Zmodyfikuj 'std :: basic_string' w standardowych nagłówkach g ++, sprawdź, czy nowy kod się kompiluje, a następnie szybko go zmień, zanim ktokolwiek zauważy. –

Odpowiedz

5

Myślę, że jest to właściwie niezdefiniowane zachowanie i nie jest sprawdzane przez kompilator. Masz szczęście, że ta implementacja zgłasza wyjątek.

Można jednak uniknąć takich problemów, określając, że chcesz domyślnych lub zerowej inicjalizacji w type-agnostykiem sposób:

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

Hm ... więc mówisz, że domyślny konstruktor typu int przypisuje 0? – pachanga

+3

Ta składnia oznacza zerową inicjalizację dla wbudowanych typów. – visitor

+0

Dzięki za informacje! – pachanga

2

Jest infrastruktura w GCC produkować dokładnie ten rodzaj ostrzeżenia:

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

void bar() { 
    foo(0); 
} 

kiedy zestawiane z -Wnonnull (który jest obserwowaną -Wall) daje:

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

Więc w zasadzie powinno Ci być w stanie zmodyfikować odpowiedni nagłówek systemu (albo lepiej do eksperymentowania, modyfikować swój własny $ HOME/bity/basic_string.h skopiować, a następnie zastąpić jeden system z -isystem $HOME) podobnie:

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

Jednak to nie pomaga, ponieważ (przynajmniej w wersji 4.0.1) -Wnonnull nie jest obsługiwane w C++, a atrybut jest najwyraźniej ignorowany. Nie jest jasne, dlaczego tak się dzieje; być może było to odczucie, że źle się z nim łączyło z przeciążeniem lub czymś podobnym.

+1

Właściwie twój 'basic_string' ctor' __attribute __ ((nonnull (1))) 'powyższy sprawdza czy wskaźnik' this' nie ma wartości 'NULL'; po prostu zmień na '__attribute __ ((nonnull (2))), aby sprawdzić, czy' __s' ma wartość inną niż null; zobacz http://gcc.gnu.org/ml/gcc/2006-04/msg00549.html – vladr

7

nie mogę wymyślić sposób, aby wykryć to w czasie kompilacji, więc napisałem funkcję konstruktora ciąg że właściwie zajmuje się zerowych wskaźników:

// 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); 
} 

Używam tego ilekroć utworzyć ciąg i jest szansa, że ​​dane wejściowe mogą mieć wartość NULL.

Powiązane problemy