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”上方令人困惑的注释的含义?