Is it bad to depend on index 0 of an empty std::string?
1 2
| std::string my_string ="";
char test = my_string[0]; |
我注意到这不会崩溃,每次我测试它,测试都是0。
我可以依赖它总是0吗? 还是随意的?
这是不好的编程吗?
编辑:
从一些评论中,我认为对此的有用性存在一些误解。
这样做的目的不是检查字符串是否为空。
不需要检查字符串是否为空。
情况是有一个字符串可能是空的也可能不是。
我只关心这个字符串的第一个字符(如果它不是空的)。
在我看来,检查字符串是否为空是不太有效,然后,如果它不是空的,请查看第一个字符。
1 2 3 4
| if (! my_string.empty())
test = my_string[0];
else
test = 0; |
相反,我只需查看第一个字符,无需检查字符串是否为空。
-
使用std::string::empty。
-
从在线参考:Accessing the value at data()+size() produces undefined behavior: There are no guarantees that a null character terminates the character sequence pointed by the value returned by this function. See string::c_str for a function that provides such guarantee.
-
@Logicrat:您要么使用旧的引用来为C ++ 98提供规则,要么查找错误的函数。
-
什么是"在线"参考资料@Logicrat?
-
为什么要将string[0]用于空字符串? 仅用于测试,请使用string::empty()。
-
请注意,您在此处使用的"技巧"可能来自曾经使用该方法测试C String是否为空的程序员。 C风格的字符串只是一个字符数组,如果第一个字符[0]为零,则该字符串为空。 这是有效的,因为C String只是一个数组而不是覆盖[]运算符的类。
-
旁白:第一个字符为零的字符串不一定是空字符串!
-
@Hurkyl我认为他正在检查(test == 0)而不是(test == '0')。 ASCII中的0是null
-
@Ahmed:std::string x ="123"; x[0] = 0; assert(x[0] == 0 && !x.empty());
-
@Hurkyl我明白你的观点,你是对的
C ++ 14
没有;你可以依靠它。
在21.4.5.2(或[string.access])中我们可以找到:
Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object leads to undefined behavior.
换句话说,当pos == size()(两者都为0时为true)时,运算符将返回对默认构造的字符类型的引用,您将禁止修改该字符类型。
对于空(或0大小)字符串,它不是特殊的,并且对于每个长度都是相同的。
C ++ 03
而且肯定也是C ++ 98。 sub>
这取决于。
这是官方ISO / IEC 14882的21.3.4.1:
Returns: If pos < size(), returns data()[pos]. Otherwise, if pos == size(), the const version returns charT(). Otherwise, the behavior is undefined.
-
请注意,在C ++ 11之前,operator[]的非const版本在这种情况下会导致未定义的行为(即使您不修改结果引用)。
-
这是一个很好的答案。您能提供有关您的来源的信息吗?
-
@BenKey:这是C ++标准本身使用的编号系统。
-
@BenKey对于第一个引用,我使用了一个非常有用的在线渲染(我认为)最后的C ++ 14草案。对于第二个,它是原始的ISO PDF。正如Ben V.指出的那样,这两个数字代表的部分都是文件。
-
但是如果返回一个引用,则意味着某个人必须构造一个char并将其初始化为0.(除非编译器对此进行优化。)是什么让C ++委员会将其作为标准?
-
在使用C ++ 03时,我不同意"它取决于"。依赖于未定义的行为总是很糟糕。可以通过更改代码来使用operator[]的const版本来逃避UB,但是显示的是使用非const重载并且这是不安全的。
-
@TobySpeight如果pos < size(),则没有未定义的行为。
-
是的,但是我们在这里看pos == size()(都等于0)。
@Bartek Banachewicz的答案解释了哪些情况允许你做出你的假设。我想补充一点
这是糟糕的编程。
为什么?有几个原因:
你必须成为一名语言律师才能确保这不是一个错误。如果不是这个页面,我不知道答案,坦率地说 - 我认为你也不应该知道。
没有字符串直觉的人是一个空终止的字符序列,在你阅读标准或询问他们的朋友之前,他们不知道你要做什么。
以不好的方式打破最小惊喜的原则。
违背"写你的意思"的原则,即让代码表达问题域概念。
对幻数的使用排序(在这种情况下,0是否实际构成幻数)是有争议的。
我要继续吗? ......我几乎可以肯定你几乎在所有方面都有另一种优势。我甚至冒昧地猜测你已经做了一些"糟糕"的事情来操纵自己想做这件事。
永远记住:其他不会咨询你的人,迟早会需要维护这段代码。想想他们,不仅仅是你自己,谁能想出来。另外,从现在开始的十年间,谁会说你会记住你自己的伎俩?你可能是那个困惑的维护者......
-
对位:人们可能希望从现在起十年后,任意指数成为std::string的有效性将是常识。
-
-1:编程也不错。定义了行为,就像s [-2]在许多语言中返回字符串中倒数第二个字符一样。是的,会有一些C ++程序员不知道这个行为已定义,并且评论可能是有序的。但如果s [0]足够,我不会添加一行代码。
-
@kevincline:定义某事的事实并不意味着应该使用它。实际上,需要对边缘情况进行特定定义的行为,以及可能完全不同的行为,往往(并非总是)更好地避免这种行为。此外,简洁性很好,但是:1。还有其他方法可以实现它。 2.你仍然必须平衡简洁,而不仅仅是牺牲前者。
-
实现减去索引将是所有必须支付但很少会使用的代码,因此它不会在C ++中实现。
-
@kevincline:s [0]或s [-2]很好,这不是问题。问题是在空字符串上使用s [0]或s [-2]或what-not。令人困惑的是:如果您知道字符串为空,为什么要尝试访问其字符?只是不要。
-
@einpoklum:这只会令人困惑一次。然后它变得惯用。
-
有些东西不会成为惯用语,因为一个人或少数人使用它。另外,我会说,一个好的成语最初并不令人困惑。
-
@einpoklum:虽然我同意你的评论的普遍性,但我不同意这个令人困惑的一点 - 特别是当混淆的根源不是关于成语实际上是什么时,而是更多关于人们过去十年的事实内化了此功能过去不存在的后果。
-
@Hurkyl:至少可以说,我不是最有经验的C ++程序员,但是我不记得有人注意到人们使用std::string本身而不是char *函数和.c_str(),试图从中获取字符一个空字符串。或者 - 也许我不太关注。
-
是否定义了行为:如果我读取类似于OP的前两行的代码,我会去WTF。请记住,即使在C ++ 14中,您也不能修改返回的引用,或者您再次使用UB。绝对糟糕,糟糕的风格。