leftaroundabout
leftaroundabout

Reputation: 120711

How do I prevent trouble arising from std::string being constructed from `0`?

void foo (const std::string &s) {}

int main() {
  foo(0);   //compiles, but invariably causes runtime error
  return 0;
}

The compiler (g++ 4.4) apparently interprets 0 as char* NULL, and constructs s by calling string::string(const char*, const Allocator &a = Allocator()). Which is of course useless, because the NULL pointer is not a valid pointer to a c-string. This misinterpretation does not arise when I try to call foo(1), this helpfully produces a compile-time error.

Is there any possibility to get such an error or warning at compile-time when I accidentally call a function like

void bar(const std::string &s, int i=1);

with bar(0), forgetting about the string, and actually meaning to have i=0?

Upvotes: 19

Views: 325

Answers (3)

graphitemaster
graphitemaster

Reputation: 3723

Actually static asserts would work too. consider this:

void foo (const std::string &s)
{
    // Your function
}

void foo(const char *s)
{
    #ifdef CPP_OH_X
    static_assert(s == 0, "Cannot pass 0 as an argument to foo!");
    #else
    typedef int[(s != 0) ? 1 : -1] check;
    #endif
    foo(std::string(s));
}

The idea here is to use static_assert which is a upcoming feature in C++ and is already implemented in various compilers; primarly the ones that support C++0x. Now if you're not using C++0x you can use the alternitive method, which basicly typedefs an integer with a negitive value on failure. Something which is not allowed and will produce an error at compile time

Upvotes: -2

Paul Manta
Paul Manta

Reputation: 31567

One somewhat clean workaround...

#include <cassert>

void foo (const std::string &s)
{
    // Your function
}

void foo(const char *s)
{
     assert(s != 0);
     foo(std::string(s));
}

Upvotes: 1

Peter Alexander
Peter Alexander

Reputation: 54270

This is kind of ugly, but you could create a template that will produce an error when instantiated:

template <typename T>
void bar(T const&)
{
    T::youHaveCalledBarWithSomethingThatIsntAStringYouIdiot();
}

void bar(std::string const& s, int i = 1)
{
    // Normal implementation
}

void bar(char const* s, int i = 1)
{
    bar(std::string(s), i);
}

Then using it:

bar(0); // produces compile time error
bar("Hello, world!"); // fine

Upvotes: 10

Related Questions