【问题标题】:Why std::string object when constructed with default constructor behaves differently?为什么使用默认构造函数构造的 std::string 对象表现不同?
【发布时间】:2020-03-06 21:13:50
【问题描述】:

我尝试了以下程序:

#include <iostream>
#include <string>

int main ()
{
  std::string str;
  str[0] = 'o';
  str[1] = 'k';
  std::cout << str.length();
  std::cout << "as a whole :";
  std::cout << str << std::endl;
  std::cout << "character by character :";
  std::cout << str[0] << str[1] << std::endl;      
  return 0;
}

我不明白为什么我不能使用对象变量作为一个整体打印字符串以及为什么长度返回为0,因为很明显我已经使用下标运算符添加了字符,因为这将返回 char 引用所以我知道这是合法的。

此外,我没有遇到任何异常。所以就是这样。显然,std::string 课程的幕后发生了很多事情,我知道我遗漏了一些东西。有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: c++ stl insert stdstring c++-standard-library


    【解决方案1】:

    我不明白为什么我不能将整个字符串打印出来 [...]...

    因为您遇到了未定义的行为

    这个

    std::string str;
    

    构造一个带有0 内存分配的默认字符串。意思是通过std::string::operator[] 修改将导致asses out of bounds undefined behaviour。因此,任何事情都可能发生。在您的情况下,长度返回0


    [...] 显然我已经使用下标运算符添加了字符 因为这会返回 char 引用,所以我知道这是合法的。

    ,由于上述原因,您没有。供参考,std::string::operator[]

    返回对指定位置 pos 的字符的引用。 没有 执行边界检查。如果 pos > size(),则行为未定义。


    作为可能的修复,您可能希望在访问元素之前std::string::resize

    #include <string>
    
    std::string str;
    str.resize(2);
    str[0] = 'o';
    str[1] = 'k';
    // ... now it has defined behaviour
    

    std::string::push_back将每个字符插入字符串。

    #include <string>
    
    std::string str;
    str.push_back('o');
    str.push_back('k');
    // ... now it has defined behaviour
    

    【讨论】:

    • 请注意,您可以访问str[0] 以获得默认构造的str。你只是不能修改它。
    • 同意,只是想从技术上澄清您的陈述。顺便说一句,请注意您与 cppreference 的链接与此处无关。在这种情况下,UB 是由与标准不同的条款引起的。即thisthis。标准此处不涉及越界数组访问(可能在内部,但未定义)。
    【解决方案2】:

    您没有向空字符串 str 添加任何内容。相反,您正在尝试编辑空字符串的不存在元素。 std::string 的下标运算符不会自动添加元素。 (不像std::map)此外,不能保证下标运算符会抛出一些异常。如果你想要安全下标操作,你可以使用std::string::at函数。

    您可以使用+= 运算符将某些内容附加到您的字符串。

    str += 'o';
    str += 'k';
    

    【讨论】:

    【解决方案3】:

    您有一个长度为0 的字符串,然后您尝试使用下标运算符修改其内容。这是未定义的行为,因此在这一点上,不能保证特定的结果。如果你改用at(),它会暴露错误并抛出异常。

    为什么长度返回为 0

    它以 0 开始,而您没有对其进行任何添加(例如 push_back+=)。但是话又说回来,由于您之前所做的是未定义的行为,因此这里可能发生任何事情。

    另外,我没有遇到任何异常。

    您可以改为尝试std::string::at,当您尝试时会抛出std::out_of_range 异常。

    【讨论】:

    • 谢谢。我仍然怀疑 str[pos] 返回那个位置的字符?
    • 它确实返回了对那个位置的字符的引用,但是在你这样做之前你必须确保字符串实际上是那么长。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 2023-03-16
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多