6

我的问题很简单,getline(istream, string) 是如何实现的?如何解决像 getline (char* s, streamsize n) 这样的固定大小的 char 数组的问题?他们是否使用临时缓冲区和对 new char[length] 或其他简洁结构的多次调用?

4

3 回答 3

9

getline(istream&, string&)以读取一行的方式实现。它没有明确的实现;每个图书馆可能彼此不同。

可能的实现:

istream& getline(istream& stream, string& str)
{
  char ch;
  str.clear();
  while (stream.get(ch) && ch != '\n')
    str.push_back(ch);
  return stream;
}
于 2012-09-04T17:32:44.403 回答
5

@SethCarnegie 是对的:不止一种实现是可能的。C++ 标准没有说明应该使用哪个。

但是,这个问题仍然很有趣。这是一个经典的计算机科学问题。当一个人事先不知道要分配多少内存时,在哪里以及如何分配内存?

  1. 一种解决方案是将字符串的字符记录为单个字符的链接列表。这既不节省内存也不快速,但它可以工作,很健壮,并且编程相对简单。但是,标准库不太可能以这种方式实现。

  2. 第二种解决方案是分配一个固定长度的缓冲区,例如 128 个字符。当缓冲区溢出时,您分配一个双倍长度、256 个字符的新缓冲区,然后将旧字符复制到新存储中,然后释放旧字符。当新缓冲区溢出时,您再次分配一个更新的双倍长度缓冲区,512 个字符,然后重复该过程;等等。

  3. 第三种解决方案结合了前两种。维护一个字符数组的链表。列表的前两个成员(比如说)每个存储 128 个字符。第三个商店256。第四个商店512,等等。这需要比其他编程更多的编程,但可能比其他任何一个都更可取,具体取决于应用程序。

可能的实现列表还在继续。

关于标准库实现,@SteveJessop 补充说“[a] 标准库的字符串不允许实现为 (1),因为operator[]字符串的复杂性要求。在 C++11 中不允许实现为(3)要么,因为字符串的连续性要求。C++ 委员会表示相信,在他们添加连续性要求时,没有有效的 C++ 实现(3)。当然,getline可以暂时用之前的字符做它喜欢的事情将它们全部添加到字符串中,但标准确实说明了字符串可以做什么。”

添加是相关的,因为虽然getline可以通过多种方式暂时存储其数据,但如果数据的最终目标是字符串,这可能与getline's 的实现有关。@SteveJessop 进一步补充说,“对于字符串本身,实现几乎必须是 (2),除了它们可以选择自己的扩展率;只要它们乘以某个常数,它们就不必每次都加倍。”

于 2012-09-04T17:41:42.857 回答
0

正如@3bdalla 所说, thb 的实现不能作为 gnu 实现。因此,我编写了自己的实现,它的工作方式与 gnu 的类似。我不知道这个变体会出现什么错误,所以需要对其进行测试。我的getline实现:

std::istream& getline(std::istream& is, std::string& s, char delim = '\n'){
    s.clear();
    char c;
    std::string temp;
    if(is.get(c)){
        temp.push_back(c);
        while((is.get(c)) && (c != delim))
            temp.push_back(c);
        if(!is.bad())
            s = temp;
        if(!is.bad() && is.eof())
            is.clear(std::ios_base::eofbit);
    }
    return is;
}
于 2020-05-05T03:57:17.053 回答