C++:string.empty() 是不是总是等价于 string == ""?

Posted

技术标签:

【中文标题】C++:string.empty() 是不是总是等价于 string == ""?【英文标题】: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 == "" 甚至无法编译。 【参考方案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有类似的做法

【讨论】:

以上是关于C++:string.empty() 是不是总是等价于 string == ""?的主要内容,如果未能解决你的问题,请参考以下文章

c# decimal类型 有没有像string.Empty那样的值?

.NET/BCL 源代码中“string.Empty”上方令人困惑的注释的含义?

C#中null""string.empty区别

NULL,"",String.Empty三者在C#中的区别

在 C++ 中对浮点变量执行算术运算时是不是总是需要使用浮点文字?

C++,bool 转换是不是总是退回到 void* 的隐式转换?