2015-08-14 8 views
5

L'ho smontato & ho provato a trovare una domanda simile anche su SO ma non ho trovato nulla di utile. Quindi, postando la mia domanda qui.Perché la conversione implicita di bool in stringa non è un errore?

considerare questo programma:

#include <iostream> 
void foo(const std::string &) {} 
int main() 
{ 
    foo(false); 
} 
 
[Warning] converting 'false' to pointer type for argument 1 of 'std::basic_string::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator]' [-Wconversion-null] 

Perché C++ permette questo senza cast esplicito? Mi aspettavo di ottenere l'errore del compilatore. Il programma termina in modo anomalo in fase di esecuzione a causa di un'eccezione visualizzazione seguente:

terminate called after throwing an instance of 'std::logic_error' 
    what(): basic_string::_S_construct null not valid 

This application has requested the Runtime to terminate it in an unusual way. 
Please contact the application's support team for more information. 

ciò che la norma dice che su questo tipo di conversione implicita?

+1

"Che cosa dice lo standard su questo tipo di conversione implicita?" Dice che è permesso. – juanchopanza

+0

@juanchopanza: No. Non è così. è necessario scrivere testo pertinente dallo standard C++. – Destructor

+5

@Downvoters: perché downvotes? Cosa c'è di sbagliato in questione? – Destructor

risposta

7

Prima che C++ 11 introducesse la parola chiave nullptr, i puntatori nulli erano un po 'un trucco. Qualsiasi numero intero letterale uguale a zero sarebbe sufficiente come costante del puntatore nullo e false si adatta alla fattura.

Quindi, l'effetto del programma è di costruire il std::string con un argomento char const * di NULL. Il costruttore non supporta i puntatori nulli, quindi si ottiene un comportamento non definito.

La soluzione a questo problema è utilizzare un dialetto più recente di C++. Passare -std=c++11 al compilatore se necessario oppure -std=c++14.Poi si dovrebbe ottenere qualcosa di simile:

error: no matching function for call to 'foo' 

http://coliru.stacked-crooked.com/a/7f3048229a1d0e5a

EDIT: Hmm, GCC non sembra ancora implementare questa modifica. Questo è un po 'sorprendente. Potresti provare Clang.

Ho una segnalazione di errore su filed.

+1

, GCC lo compila ancora con C++ 11 o C++ 14 abilitati. – Quentin

+3

@Quentin, emette una diagnostica, che è tecnicamente tutto ciò che è necessario per un programma mal formato. Preferirei se fosse un errore, non un avvertimento però. –

+2

@JonathanWakely Ma che dire di SFINAE e sovraccaricare l'ordine parziale? Sono pigro per testare con un esempio specifico ora, mi dispiace. – Potatoswatter

-1

Un bool è fondamentalmente un intero così sarà interpretato come uno zero, in caso è probablly il carattere 0 e questo farà sì che il problema stringa un'eccezione

3

ciò che accade è che un std::string è implicitamente costruito da false, utilizzando il sovraccarico const CharT* e convertendo false in un puntatore nullo. Secondo la documentazione per tale costruttore:

Il comportamento è indefinito se s [il puntatore] non punta ad un array di almeno Traits::length(s)+1 elementi di CharT.

Quindi il malfunzionamento (sotto forma di un'eccezione amichevole, ma non fare affidamento su di esso).

Ora, è corretto? Secondo [conv.ptr]:

Un puntatore nullo costante è un intero letterale (2.13.2) con valore zero o un prvalue di tipo std::nullptr_t.

false ha effettivamente un valore pari a zero, ma non è un valore letterale intero (è un valore letterale booleano). La conversione implicita allo CharT* presa dal costruttore di std::string è quindi non standard.

E infatti, mentre GCC emette un avviso, Clang si rifiuta di compilarlo.

+2

Clang lo compila se si specifica '-std = C++ 03'. Dipende solo da quale dialetto è l'impostazione predefinita per la particolare versione del compilatore. – Potatoswatter

+0

@Potatoswatter Ma la domanda non cita C++ 03. In C++ 11 e oltre, solo il letterale '0' può essere convertito in un puntatore nullo. – Quentin

+0

@ Quentin: perché dici che non si basano sulla forma di eccezione amichevole? – Destructor