【问题标题】:Is this expression valid?这个表达式有效吗?
【发布时间】:2015-12-17 15:52:22
【问题描述】:

我遇到了这个代码:

std::string str;
std::getline(std::cin, str);
std::string sub = str.substr(str.find('.') + 1);

第一反应是 - 这是无效代码。但经过一番思考,似乎并没有那么简单。那么它是有效的 C++ 表达式(具有可预测的行为)吗?

PS 如果不是很清楚,问题主要与'.' 时会发生什么有关。在str 中找不到,但不限于此,可能还有其他问题。

【问题讨论】:

  • 字面意思和上面一样吗,里面有...?!?还是关于substr 行的问题?
  • 第一反应是 - 这是无效代码。 为什么?
  • @Slava 好吧,你是那个声称你对明显无效的代码感到惊讶的人。 substr 行对我来说一点也不奇怪。通过使用 ... 而不是 "foobarbaz",您违反了基本规则并且未能提供 SSCCE。
  • 您是否费心查找文档?我不明白你为什么觉得有必要发布这个问题。 std::string::find, std::string::substr
  • @Slava,那么请继续将这条重要信息添加到您的问题中。

标签: c++ string integer-overflow


【解决方案1】:

str.find('.') 返回字符串中字符第一次出现的索引。 substr 带有一个参数,返回从给定索引开始的字符串的后缀。所以该行的作用是返回从第一个点之后开始的字符串的尾部。所以如果str"hello.good.bye"sub 将是good.bye

但是,如果字符串实际上不包含任何点,则 可能存在代码问题。它将返回整个字符串。这可能是也可能不是有意的。这是因为如果没有点,find 将返回npos,这是std::string::size_type 可以容纳的最大数字。将1 添加到其中,您将得到 0(这就是无符号类型的行为方式,模 2n)。

所以代码总是具有可预测的行为。

【讨论】:

  • 如果没有'.',你会得到npos,我认为你不能合法地+1
  • @BoBTFish 标准中没有定义无符号整数溢出吗?
  • @NathanOliver 正确。我不得不再考虑几秒钟。
  • @BoBTFish 我还在完成我的答案。
【解决方案2】:

http://en.cppreference.com/w/cpp/string/basic_string/npos 看来,std::string::npos = -1;。当find 不成功时返回该值。在这种情况下,str.substr(0) 将返回整个字符串。

这似乎是有效且可预测的代码。

【讨论】:

    【解决方案3】:

    如果您询问如果找不到. 会发生什么,您不必担心。 std::string::find然后返回std::string::npos,标准定义为-1,加上1后溢出,使得参数0

    std::string sub = str.substr(0);
    

    它为您提供了整个字符串。我不知道这是否是期望的行为,但它肯定不是未定义的行为。

    【讨论】:

    • npos 不能为 -1 它的类型为 size_t
    • 无论哪种方式都会溢出到0,不是吗?
    • @Slava 标准将npos 定义为size_type npos = -1
    • @Slava -1 作为一个无符号被很好地定义为1 的加法逆。因此,在无符号类型中,-1 不是负数,但它是添加 1 的值,将为您提供 0
    【解决方案4】:

    实际上,在这种特定情况下——因为包含“...无关紧要...”的字符串实际上确实如此——find() 调用不会找到它正在寻找的内容,因此会返回std::string::npos。然后将其加 1。

    npos 的类型为std::string::size_type,一般为size_t,通常是某种无符号整数。

    npos 被定义为size_type 的最大可能值。

    size_type 是无符号的,最大可能值加 1 会产生 0。

    所以你打电话给std::string::substr(0)。这是做什么的?它会创建您调用它的整个字符串的副本,因为substr 采用起始位置和长度(默认为npos,或“一直到结束”)。

    【讨论】:

      【解决方案5】:

      据我所知,虽然它不是特别可读,但它是有效的。

      如果str 为空,则find() 方法将返回std::string::npos。这相当于std::size_type 可以表示的最大unsigned int。通过将 1 添加到此,您将导致整数溢出,它将环绕为 0。这意味着 substr() 方法正在尝试使用从位置 0 到字符串末尾的字符创建字符串。如果str 为空,则sub 也为空。

      【讨论】:

        猜你喜欢
        • 2014-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多