Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why implicit conversion of bool to string isn't an error?

I goggled it & tried to find similar question on SO also but didn't find anything useful. So, posting my question here.

Consider this program:

#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]

Why C++ allows this without explicit cast? I was expecting to get compiler error. The program abnormally terminates at runtime due to exception displaying following:

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.

What the standard says about this type of implicit conversion?

like image 263
Destructor Avatar asked Aug 14 '15 12:08

Destructor


Video Answer


2 Answers

Before C++11 introduced the nullptr keyword, null pointers were a bit of a hack. Any integer literal equal to zero would suffice as a null pointer constant, and false fit the bill.

So, the effect of your program is to construct the std::string with a char const * argument of NULL. The constructor doesn't support null pointers, so you get undefined behavior.

The solution to this problem is to use a newer dialect of C++. Pass -std=c++11 to the compiler if necessary, or -std=c++14. Then you should get something like this:

error: no matching function for call to 'foo'

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

EDIT: Hmm, GCC doesn't appear to implement this change yet. That's a bit surprising. You might try Clang.

I've filed a bug report.

like image 117
Potatoswatter Avatar answered Nov 09 '22 11:11

Potatoswatter


What happens is that an std::string is implicitly constructed from false, using the const CharT* overload and converting false to a null pointer. According to the documentation for that constructor :

The behavior is undefined if s [the pointer] does not point at an array of at least Traits::length(s)+1 elements of CharT.

Hence the malfunctioning (in the form of a friendly exception, but don't rely on it).

Now, is it correct ? According to [conv.ptr] :

A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t.

false has indeed a value of zero, but is not an integer literal (it's a boolean literal). The implicit conversion to the CharT* that std::string's constructor takes is thus non-standard.

And indeed, while GCC emits a warning, Clang refuses to compile it.

like image 44
Quentin Avatar answered Nov 09 '22 12:11

Quentin