I'm trying to work through ways to create a class with a std::string argument, but which also handles NULL without throwing an exception. Here's an example of the code:
class myString {
public:
myString(const std::string& str) : _str(str) {}
std::string _str;
};
int main() {
myString mystr(NULL);
printf("mystr = <%s>\n", mystr._str.c_str());
return 0;
}
Intuitively, you'd think that this program should print "mystr = <>" and exit successfully, but instead with g++ it gives this error:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid
How can I change this class so that it translates NULL into "" instead of throwing a logic_error exception?
(Postscript: As you'd suspect, the "real" implementation is a bit more complicated than this example, having several arguments in the constructor and doing more interesting things with _str -- and properly keeping it private. The motivation behind this example is that programmers in our team will tend to use NULL in this context for historical purposes, and the compiler won't catch th开发者_运维技巧is. Retraining everyone to always use "" is relatively hard. Alternatively, a clever solution would be easy)
What actually happens here is that NULL
is interpreted as char const*
and is being tried to be converted to std::string
(you can convert C-strings of type char*
into STL strings, right?).
To handle it, you may add another constructor
class myString {
public:
myString(const std::string& str) : _str(str) {}
myString(const char* str) : _str(str==NULL?"":std::string(str))
{ /* and do something special in the body */ }
std::string _str;
};
But if you need nothing special there, the better way would be
class myString {
public:
myString(const std::string& str = "") : _str(str) {}
std::string _str;
};
int main() {
myString mystr; //no () here!
printf("mystr = <%s>\n", mystr._str.c_str());
return 0;
}
Really, you can't. NULL is not a string. But here are some alternatives:
You could overload your constructor to omit the string argument.
You could use a pointer instead of a reference.
You could default the string argument to "".
You cannot. You need to have something to be able to pass a reference to. You could though work around this by defaulting to null-strings aka ""
.
Alternatively, have another explicit
ctor:
class myString {
public:
myString(const std::string& str) : _str(str) {}
explicit myString(const char* str = NULL) : _str(str?str:"") {}
std::string _str;
};
You need to provide a constructor that accepts a pointer as an argument. NULL is a pointer, not a reference, and so as you've seen disaster will result if you try to treat it as a string reference.
Try:
class myString {
public:
myString(const std::string& str) : _str(str) {}
myString(const std::string* str) : { /* special-case logic here */}
std::string _str;
};
I'll assume this problem isn't as simple as your example appears to be.
Instead of using a NULL parameter, you can create a static variable and assign to that.
class myString {
public:
static std::string nullstring;
...
};
and somewhere in a .cpp:
std::string myString::nullstring("");
And to call it:
int main() {
myString mystr(myString::nullstring);
printf("mystr = <%s>\n", mystr._str.c_str());
return 0;
}
精彩评论