【问题标题】:C++: is string.empty() always equivalent to string == ""?C++:string.empty() 是否总是等价于 string == ""?
【发布时间】:2009-01-27 13:10:26
【问题描述】:

我可以假设给定

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

以下陈述是否总是正确的?

(str.empty() == (str == ""))

【问题讨论】:

  • str.empty() 更通用。如果有一天你决定使用std::wstring str,那么str.empty() 可以工作,但str == "" 甚至无法编译。

标签: c++ string


【解决方案1】:

回答

是的。这里是来自bits/basic_string.h的相关实现,basic_string<_CharT, _Traits, _Alloc>的代码:

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

讨论

尽管std::string 这两种形式是等价的,您可能希望使用.empty(),因为它更通用。

确实,J.F. Sebastian 表示如果你切换到使用std::wstring 而不是std::string,那么=="" 甚至不会编译,因为你无法将wchar_t 的字符串与@ 中的一个进行比较987654331@。但是,这与您最初的问题没有直接关系,我 99% 确定您不会切换到 std::wstring

【讨论】:

  • @xtofl:原始问题的答案,仅询问 std::string,是明确的“是”。
  • 另外,empty() 应该比 =="" 更有效率。
  • 由于某种原因,这个答案对我来说似乎非常特定于编译器/供应商
  • @A.雷克斯:这意味着他的答案是应该投票的,而不是你的。 ;) 在 C++ 中,相信您的编译器/实现来说明语言的行为方式通常是错误的。它所能告诉您的只是 您的 实现的行为方式,而不是该行为是否 1) 正确和 2) 必需。
  • 不要太确定不要切换到 std::wstring。您永远不知道公司总部何时会想要开设日本分支机构。
【解决方案2】:

应该是的。 ANSI/ISO 标准在21.3.3 basic_string capacity 中声明:

size_type size() const;

返回:字符串中当前类似字符的对象的计数。

bool empty() const;

返回: size() == 0

但是,在21.3.1 basic_string constructors 的第 18 条中,它指出字符类型赋值运算符使用traits::length() 来确定受控序列的长度,因此如果您使用不同的 @ 特化,最终可能会出现一些奇怪的情况987654329@.

我认为 100% 正确的说法是

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

或类似的东西。如果你没做过什么奇怪的事情,那么std::string("")std::string()应该是等价的

它们在逻辑上相似,但它们正在测试不同的东西。 str.empty() 正在检查字符串是否为空,而另一个正在检查 C 样式的空字符串是否相等。我会使用更适合您尝试做的事情。如果您想知道字符串是否为空,请使用str.empty()

【讨论】:

    【解决方案3】:

    str.empty() 永远不会慢,但可能比 str == "" 快。这取决于实施。所以你应该使用 str.empty() 以防万一。

    这有点像使用 ++i 而不是 i++ 来增加计数器(假设您不需要递增运算符本身的结果)。您的编译器可能会优化,但使用 ++i 不会损失任何东西,并且可能会有所收获,因此最好使用 ++i。

    除了性能问题,您的问题的答案是肯定的;这两个表达式在逻辑上是等价的。

    【讨论】:

      【解决方案4】:

      是的,(str.empty() == (str == "")) 对于std::string 始终*为真。但请记住,string 可以包含 '\0' 字符。因此,即使表达式 s == "" 可能为假,s.c_str() 仍可能返回一个空的 C 字符串。例如:

      #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;
      }
      

      **除非在全局命名空间中operator== 重载,正如其他人所提到的*

      【讨论】:

        【解决方案5】:

        某些实现可能会将空字符作为字符串中的第一个字符进行测试,从而导致计算字符串大小的速度略有提高。

        我相信这并不常见。

        【讨论】:

        • 我希望它永远不会发生,因为 C++ 字符串声称能够存储任何字符,包括可能的空字符。
        • 同意 A. Rex。 size() 应该是 O(1),即无论如何存储。
        • A. Rex,如果您使用 =="c 样式字符串",它将在第一个 \0 处停止比较。所以优化实际上是非常有效的。
        • 由于 A. Rex 的观点 - 检查 NUL 只能在 const char* 参数上完成;您仍然需要检查字符串本身是否为空,因此您必须添加工作而不是仅测试空。
        【解决方案6】:

        通常,是的。

        但如果有人决定重新定义一个运算符,那么所有的赌注都没有了:

        bool operator == (const std::string& a, const char b[])
        {
            return a != b; // paging www.thedailywtf.com
        }
        

        【讨论】:

        • 有人可以很容易地更改 empty() ...甚至整个 STL 的所有其余部分 ...
        • 实际上,如果这个操作符是全局定义的,这将比改变整个 STL 容易得多。我不知道在这种情况下它是否会覆盖在 std::string 对象上定义的运算符,但是...
        • 是的,我的意思是,C++ 允许您通过糟糕地重新定义运算符来一劳永逸,因此回答上述问题将不可避免地依赖于警告。
        • 我实际上给了这个+1(部分是为了提到thedailywtf.com!)。我什至见过有人根据 operator> 为优先级类型定义 operator
        【解决方案7】:

        是的,它是等效的,但允许核心代码根据操作系统/硬件/任何东西更改 empty() 实际含义的实现,并且根本不会影响您的代码。 Java和.NET有类似的做法

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-04
          • 1970-01-01
          • 2010-11-06
          • 1970-01-01
          • 2015-03-31
          • 1970-01-01
          • 1970-01-01
          • 2010-09-28
          相关资源
          最近更新 更多