25

Due to a bug, I just found out that this code compiles fine on with Visual Studio 17 and probably on other compilers as well. Now I'm curious why?

#include <iostream>
#include <string>

std::string foo(){
    return nullptr;
}

int main(){
    auto s = foo();
    std::cout << s << std::endl;
}

I could imagine it is because the std::basic_string c'tor could be invoked with a char* and while returning an implicit conversion from ptr to std::string occurs (with NULL as argument and then goes poof). Am I on the right way?

Marc.2377
  • 7,807
  • 7
  • 51
  • 95
Taron
  • 1,205
  • 2
  • 13
  • 29
  • 1
    it is probably indeed passing `nullptr` as the parameter for a pointer – Tarick Welling Jun 17 '19 at 11:42
  • 2
    It compiles, but you get a runtime error. – t.niese Jun 17 '19 at 11:42
  • 16
    It would probably be beneficial to add a `string (nullptr_t) = delete` ctor, just so this error is caught at compile time. I don't think legitimate programs would break due to that. – MSalters Jun 17 '19 at 12:03
  • Related, [Why does constructing std::string(0) not emit a compiler warning?](https://stackoverflow.com/q/13394212/608639), [Access Violation when sending a 0 int literal to a const string parameter](https://stackoverflow.com/q/48210211/608639), [Avoiding improper std::string initialization with NULL const char* using g++](https://stackoverflow.com/q/2407711/608639), [How to best protect from 0 passed to std::string parameters?](https://softwareengineering.stackexchange.com/q/220687/118658), etc. – jww Jun 18 '19 at 00:37

2 Answers2

24

Yes, your assumption is right, checking std::basic_string constructors #5 will be called:

basic_string( const CharT* s,
              const Allocator& alloc = Allocator() );

Note that passing nullptr invokes undefined behavior as stated in the standard and the notes :

The behavior is undefined if [s, s + Traits::length(s)) is not a valid range (for example, if s is a null pointer).

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • Interesting enough, std::string_view's constructor has __attribute__((__nonnull__)) and the compiler emits a warning when NULL or nullptr is passed to the std::string_view's constructor. I wonder, why there is no such attribute for std::string's constructor – Nuclear Nov 19 '21 at 11:05
13

Why shouldn't it compile? std::string has the following constructor:

string(const CharT* s, const Allocator& alloc = Allocator());

that constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The constructor is not explicit, so the implicit conversion from nullptr to std::string is indeed possible.

Evg
  • 25,259
  • 5
  • 41
  • 83
  • 1
    Please note that passing __null__ is UB – Richard Critten Jun 17 '19 at 11:59
  • 16
    @RichardCritten, it definitely is. But the question was why this code compiles, not what happens if the code is executed. UB will happen not only for `nullptr`, but for any pointer that doesn't point to the beginning of a null-terminated string. – Evg Jun 17 '19 at 12:13