Sign in to follow this  
Kiput

std::string == NULL?

Recommended Posts

Hi. I want to convert strings in my old project to std::string (char *'s are my main source of crashes), so I change my classes from something like this: class foo { char * str; }; To this: class foo { string str; } The problem is that code is full of things like this: if( str == NULL ) DoSomething( ); // Or this if( !str ) DoSomething( ); With std::string I have to change that to: if( str.empty( ) ) DoSomething( ); I don't want to do that - I have lots of this crap in my code, so it's just too much work. Does something like this would be possible (considering that I don't use "string *" anywhere): // Yes, I know this doesn't work =P bool string::operator== ( int i ) { if( i == NULL ) return empty( ); else return !empty( ); } I'm still a bit newbie to Cpp and STL so pardon me if I'm missing something (probably some easy solution =]). And yes, I tried googling. =)

Share this post


Link to post
Share on other sites
Quote:
Original post by Miracle Dog
Couldn't you just do a simple search and replace, or am I missing something obvious?


I would have to replace it by hand, and considering I'm lazy bum, I prefer not to do this. Besides, I think that "!str" is cleaner (and it's less typing) that "str.empty( )".

[edit]Vanishing posts, eh? =][/edit]

Share this post


Link to post
Share on other sites
#define NULL std::string()

It'll break everything else that uses NULL...

The less breaky way to do this would be to use your IDE's search and replace feature to do this, and check that you are indeed comparing against a string there.

It'll be a tiny bit slower that simply checking .empty(), but that probably isn't a problem unless you're doing string comparions in the innermost loop of your rendering code or similar... in which case you've probably got bigger problems anyways :-).

Also:

bool operator!( const std::string & string ) {
return !string.empty();
}


That'll deal with your "if ( ! string )" issues, although there's no way to deal with (that I'm aware of) "if ( string )", since at least using GCC, "operator bool" can't be a non-member or static function. For this you could use the "double-bang trick", by switching "if ( string )" to "if ( !! string )"...



...


If you want to do something really stupid, you could do this:

class null_type
{
public:
operator std::string( void ) const {
return std::string();
}
operator void * ( void ) const {
return 0;
}
};

#ifdef NULL
#undef NULL
#endif //def NULL
#define NULL (null_type())



But that's a pretty ugly hack :-).

Share this post


Link to post
Share on other sites
"Templatised null-on-crack" to the rescue [lol]
#if !defined(NULL_PTR_HEADER)
#define NULL_PTR_HEADER

#undef NULL

#include <string>

namespace
{

typedef bool boolean;

class NullPtr
{

public:

template < typename TYPE >
operator TYPE *() const
{
return 0;
}

template < typename CLASS, typename TYPE >
operator TYPE CLASS:: *() const
{
return 0;
}

private:

void operator &() const;
void operator *() const;
void * operator->() const;

};

template < typename TYPE >
boolean operator==(TYPE const * const pointer, NullPtr const & nullPointer)
{
return pointer == static_cast< TYPE * >(nullPointer);
}

template < typename TYPE >
boolean operator==(NullPtr const & nullPointer, TYPE const * const pointer)
{
return pointer == static_cast< TYPE * >(nullPointer);
}

boolean operator==(std::string const & string, NullPtr const &)
{
return string.empty();
}

boolean operator==(NullPtr const &, std::string const & string)
{
return string.empty();
}

template < typename TYPE >
boolean operator!=(TYPE const * const pointer, NullPtr const & nullPointer)
{
return pointer != static_cast< TYPE * >(nullPointer);
}

template < typename TYPE >
boolean operator!=(NullPtr const & nullPointer, TYPE const * const pointer)
{
return pointer != static_cast< TYPE * >(nullPointer);
}

boolean operator!=(std::string const & string, NullPtr const &)
{
return !string.empty();
}

boolean operator!=(NullPtr const &, std::string const & string)
{
return !string.empty();
}

NullPtr const NULL = NullPtr();

}

#endif



Enigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
"Templatised null-on-crack" to the rescue [lol]
*** Source Snippet Removed ***

Enigma


It would be nice if it worked in VCpp6. From what I see it works only in gcc.
MaulingMonkey's hack doesn't work in either. =)
And I don't really care if it will run slow.

ps: Rated up both of you. =)

[edit]Ok. Works nicely on newer VCpp. Thanks.[/edit]

[Edited by - Kiput on May 28, 2005 5:59:12 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Kiput
// Yes, I know this doesn't work =P
bool string::operator== ( int i )
{
if( i == NULL ) return empty( );
else return !empty( );
}

I'm still a bit newbie to Cpp and STL so pardon me if I'm missing something (probably some easy solution =]). And yes, I tried googling. =)


That doesn't work because you're trying to define a member function which doesn't exist. You can, however define operator == in the global namespace(This is how operator<< for cout are defined), meaning you can do this:


bool operator == (std::string const& s, int /* or perhaps void* */){
return s.empty();
}
bool operator != (std::string const& s, int /* or perhaps void* */){
return !s.empty();
}


I tested it on the Comeau C++ compilers's web compiler, and it compiled; but it doesn't link the code, so I don't know if it will work at runtime.

You can also you MaulingMonkey's operator ! trick, then you can do if(!str) or if(!!str), but not if(str), since operator bool must be a member function.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kiput
With std::string I have to change that to:
if( str.empty( ) ) DoSomething( );

I don't want to do that - I have lots of this crap in my code, so it's just too much work.


You're probably going to run into a lot more issues than the one you just described. For instance, everyywhere you pass your old string you'll have to change to pass str.c_str(). Everywhere you get the length of the string, you'll have to change your code, and so on.

Presumably, you're switching to std::string to make your code easier to work with and/or more robust. Doing a bunch of hacky stuff to make std::string behave like a char* in your code seems like it will trade one set of problems for another set of problems that is more obscure to track down and fix.

To be completely honest, I'd either stick with the char* you have or completely bite the bullet and change all your code to use the string syntax directly.

Just my 2 cents...

-John

Share this post


Link to post
Share on other sites
I notice this hasn't been said yet: the two are not equivalent! In fact, there is no equivalent for null pointers using std::string.

In particular,

("" == NULL) is false
std::string( "" ).empty( ) is true

Besides, checking for null pointers is part of your memory management scheme, it shouldn't have anything to do with a string manipulation algorithm.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
I notice this hasn't been said yet: the two are not equivalent! In fact, there is no equivalent for null pointers using std::string.

In particular,

("" == NULL) is false
std::string( "" ).empty( ) is true

Besides, checking for null pointers is part of your memory management scheme, it shouldn't have anything to do with a string manipulation algorithm.


Indeed. Thankyou for making that point. I had intended to state that in my previous post but forgot.

I would like to point out that I posted that NULL class with string comparison only because it makes sense for the OPs scenario, upgrading a legacy program where a complete or significant rewrite is not feasible.

In fact for situations where legacy zero-terminated char * strings are being upgraded to std::strings and correction of !string and string == NULL is not feasible you can actually go one better. Declare the string containing a single character zero to be the null string. Since a zero-terminated char * cannot contain character zero but a std::string can this enables you to safely determine the difference between a null and empty string.
std::string const nullString("\0", 1);

void charPointerFunction()
{
// readLineFromFile might legitimately return an empty string and returns null if the file is not found
char * someString = readLineFromFile();
if (someString == NULL)
{
// handle error
}
else if (std::strcmp(someString, "") == 0)
{
// handle empty line
}
else
{
// handle line
}
}

void stringFunction()
{
// readLineFromFile might legitimately return an empty string and returns the null string if the file is not found
std::string someString = readLineFromFile();
if (someString == nullString)
{
// handle error
}
else if (someString == "")
{
// handle empty line
}
else
{
// handle line
}
}


Enigma

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this