tags:

views:

3826

answers:

7

Can I make an assumption that given

std::string str;
... // do something to str

Is the following statement is always true?

(str.empty() == (str == ""))
+17  A: 

Answer

Yes. Here is the relevant implementation from bits/basic_string.h, the code for basic_string<_CharT, _Traits, _Alloc>:

  /**
   *  Returns true if the %string is empty.  Equivalent to *this == "".
   */
  bool
  empty() const
  { return this->size() == 0; }

Discussion

Even though the two forms are equivalent for std::string, you may wish to use .empty() because it is more general.

Indeed, J.F. Sebastian comments that if you switch to using std::wstring instead of std::string, then =="" won't even compile, because you can't compare a string of wchar_t with one of char. This, however, is not directly relevant to your original question, and I am 99% sure you will not switch to std::wstring.

A. Rex
So basically you say: Yes, but... No.
xtofl
@xtofl: The answer to the original question, which only asked about std::string, is unambiguously "yes".
A. Rex
Also, empty() should potentially be more efficient than =="".
Ates Goral
Thanks for including the bit about std:wstring - helps me out!
Abtin Forouzandeh
this answers seems very compiler-/vendor-specific to me for some reason
@slavy13: That's true. But @D.Shawley shows that this is in line with the standard.
A. Rex
@A. Rex: Which means that his answer is the one that should be voted, and not yours. ;)In C++, it is usually a mistake to trust your compiler/implementation to say anything about how the language should behave. All it can tell you is how *your* implementation behaves, not whether that behavior is 1) correct, and 2) required.
jalf
Don't be so sure about not switching to std::wstring. You never know when corporate HQ will want to open a Japanese affiliate.
David Thornley
A: 

Yes it is equivalent but allows the core code to change the implementation of what empty() actually means depending on OS/Hardware/anything and not affect your code at all. There is similiar practice in Java and .NET

Ray Booysen
+1  A: 

Some implementations might test for the null character as the first character in the string resulting in a slight speed increase over calculating the size of the string.

I believe that this is not common however.

Jesse Dearing
I would hope it *never* happens, because C++ strings claim to be able to store any characters, including possibly null characters.
A. Rex
Agree with A. Rex. size() should be O(1), i.e. stored anyway.
MSalters
A. Rex, if you use the =="c style string", it stops comparing at the first \0 . so the optimization would be quite valid actualy.
Johannes Schaub - litb
A: 

Normally, yes.

But if someone decides to redefine an operator then all bets are off:

bool operator == (const std::string& a, const char b[])
{
    return a != b; // paging www.thedailywtf.com
}
therefromhere
Someone could just as easily change empty() ... or even all of the rest of the entire STL ...
A. Rex
actually, if this operator would be defined globally, it would be significantly easier than changing the entire STL. I don't know if it would override the operator defined on the std::string object in that case, however...
rmeador
Yeah, my point was that C++ allows you to shoot your whole foot off by redefining operators badly, so answering questions like the above will inevitably rely on caveats.
therefromhere
I'm actually giving this a +1 (partly for mentioning thedailywtf.com!). I've even seen somebody defining an operator< for a priority type in terms of operator>
Steve Folly
+2  A: 

str.empty() is never slower, but might be faster than str == "". This depends on implementation. So you should use str.empty() just in case.

This is a bit like using ++i instead of i++ to increase a counter (assuming you do not need the result of the increment operator itself). Your compiler might optimise, but you lose nothing using ++i, and might win something, so you are better off using ++i.

Apart from performance issues, the answer to your question is yes; both expressions are logically equivalent.

Gorpik
+7  A: 

It should be. The ANSI/ISO standard states in 21.3.3 basic_string capacity:

size_type size() const;

Returns: a count of char-like objects currently in the string.

bool empty() const;

Returns: size() == 0

However, in clause 18 of 21.3.1 basic_string constructors it states that the character-type assignment operator uses traits::length() to establish the length of the controlled sequence so you could end up with something strange if you are using a different specialization of std::basic_string<>.

I think that the 100% correct statement is that

(str.empty() == (str == std::string()))

or something like that. If you haven't done anything strange, then std::string("") and std::string() should be equivalent

They are logically similar but they are testing for different things. str.empty() is checking if the string is empty where the other is checking for equality against a C-style empty string. I would use whichever is more appropriate for what you are trying to do. If you want to know if a string is empty, then use str.empty().

D.Shawley
+1  A: 

Yes (str.empty() == (str == "")) is always* true for std::string. But remember that a string can contain '\0' characters. So even though the expression s == "" may be false, s.c_str() may still return an empty C-string. For example:

#include <string>
#include <iostream>
using namespace std;

void test( const string & s ) {
    bool bempty = s.empty();
    bool beq = std::operator==(s, ""); // avoid global namespace operator==
    const char * res = (bempty == beq ) ? "PASS" : "FAIL";
    const char * isempty = bempty ? "    empty " : "NOT empty ";
    const char * iseq = beq ? "    == \"\"" : "NOT == \"\"";
    cout << res << " size=" << s.size();
    cout << " c_str=\"" << s.c_str() << "\" ";
    cout << isempty << iseq << endl;
}

int main() {
    string s;          test(s); // PASS size=0 c_str=""     empty     == ""
    s.push_back('\0'); test(s); // PASS size=1 c_str="" NOT empty NOT == ""
    s.push_back('x');  test(s); // PASS size=2 c_str="" NOT empty NOT == ""
    s.push_back('\0'); test(s); // PASS size=3 c_str="" NOT empty NOT == ""
    s.push_back('y');  test(s); // PASS size=4 c_str="" NOT empty NOT == ""
    return 0;
}

*barring an overload of operator== in the global namespace, as others have mentioned

jwfearn