1

To understand more using directives and function overloading I've tried this program:

namespace ns{
    void f(int){cout << "int\n";}
    void f(double){cout << "double\n";}
    void f(std::string){cout << "string\n";}
    struct Foo{};
}

void f(ns::Foo const&){
    cout << "ns::Foo\n";
}

namespace bin{
    void f(int*){
        std::cout << "bin::f(int*)\n";
    }
}


int main(){

    using namespace ns;
    //using namespace bin;

    f(7); // int
    f(7.5); // double

    f(ns::Foo{}); // ns::Foo

    try{
        f(nullptr);
    }
    catch(std::exception const& e){
        std::cout << e.what() << std::endl;
    }
}

When I run the program, it works fine, except for the last call to f(nullptr) which causes a runtime error:

int
double
ns::Foo
basic_string::_M_construct null not valid

If I un-comment the using directive for namespace bin, then the code works fine.

using namespace bin;

The output:

int
double
ns::Foo
bin::f(int*)
3
  • 2
    void f(std::string) will erroneously try and convert char* to std::string. Commented Apr 6, 2021 at 22:48
  • You can unfortunately do the same thing with f(0). Any other number will be caught by the compiler as an illegal integer-to-string conversion, but the historical relationship between NULL and 0 gets in the way here. Commented Apr 6, 2021 at 22:55
  • 2
    when using namespace bin your f(int*) is better match (no conversion) and then the fact that string( const char* ) errors does not matter. Commented Apr 6, 2021 at 23:12

1 Answer 1

4

When using namespace bin; is commented out, there is only 1 version of f() available that can take a nullptr as input. nullptr is not implicitly convertible to int or double, so ns::f(int) and ns::f(double) are ruled out. But std::string can be constructed from a const char*, and nullptr is implicitly convertible to const char*, so the compiler can construct a temporary std::string object to pass to ns::f(std::string). However, it is undefined behavior to construct a std::string from a null const char*, hence the runtime error (which is NOT guaranteed, BTW, as the behavior is undefined, so anything can happen).

When using namespace bin; is not commented out, there are 2 versions of f() available that can take a nullptr as input. bin::f(int*) is a better match than ns::f(std::string), as nullptr is implicitly convertible to int*, so there is no need to construct a temporary object, thus the compiler chooses to call bin::f(int*) instead of ns::f(std::string).

Sign up to request clarification or add additional context in comments.

5 Comments

Ok Thank you. So you mean that std::string constructor that takes a constant character string always de-reference that argument (char const*)? So I think that that string constructor checks its argument (pointer) for a null-terminator as a sing of end of string that is why it de-reference it even being null? So a possible implementation r overload of that ctor is to provide a separate argument as the size. At that point we can decide to de-reference or not that pointer. (if 0 don't de-reference otherwise do it)? are my thought correct?
And that constructor takes a single pointer to character string (std::string(char const*);) and is not explicit to allow Implicit Conversion for (char const* to std::string) through Copy-Initialization for a const char* e.g std::string str = "Hi there!"; ?
What the std::string(const char*) constructor does when it is given a null pointer is undefined. It MAY dereference the pointer, or it MAY NOT. That is up to the implementation to decide. If you want to avoid this issue, you could provide an ns::f(const char*) overload and check for null yourself. But then you will have an ambiguity error if using namespace bin; is used, unless you explicitly typecast the nullptr to char* to int*.
So you mean the implementation is responsible on how to initialize data members of class std::string from a pointer to char char const*?
Yes, the standard does not say what the std::string constructor must do, so the implementation can do whatever it wants. Some implementations treat a null pointer as a 0-length string. Some don't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.