为什么有两个不同的getline()函数(如果确实存在)?

31

每次我写一小段C++代码时

std::string s;
cin >> s;

我自责,因为我忘记了它在空格处停止而不是获取整行。

然后,想起getline时,我总会对两种变体感到困惑:

std::string s;
getline (std::cin, s);

并且:

char cs[256];
std::cin.getline (cs, sizeof (cs));
这两者除了数据类型之外,实际上有区别吗?
在我看来,C++ 的方式应该是前者。在什么情况下我会使用后者,考虑到我可能应该使用真正的字符串而不是以空字符结尾的字符数组呢?
而且,由于输入应该是输入流的职责,那么为什么前者不是 istream 的一部分呢?
6个回答

31

所以,如果它只输入字符串,为什么不是s.getline(std::cin)而是破坏了我可爱的object.method()世界观呢? - paxdiablo
4
可能是一个语义问题:getline() 是一个流操作,而不是字符串操作,因此将其作为 std::string 类的方法似乎有些奇怪。 - Frédéric Hamidi
7
我猜测<iostream>不知道<string>,因此std::cin无法具有返回std::string的方法。 - Grozz
1
@Grozz,确实,这两个类没有耦合。 - Frédéric Hamidi
1
为什么不是s.getline(std::cin)呢?因为让std::string的实现依赖于std::istream比反过来更糟糕。"打破我可爱的对象.方法()世界观",请查阅"泄漏抽象"和"多重分派"。这种软件视角从一开始就是错误的。 - Jim Balter

12
请注意,标准库由三个(主要)部分组成:IOStream、String和STL,加上一些额外的好东西和C头文件。
我认为这些部分之间松散耦合并不奇怪(虽然我希望不是这样)。
其他不协调的地方包括:std::string::lengthstd::string::size,后者是为了与STL的接口兼容而添加的,前者是为了与旧代码兼容而保留的。

3
我认为这个词组应该是“松耦合”,而“不良集成”有消极的含义。我认为能够在不需要 std::istream 的情况下使用 std::string,并且在不需要 std::string 的情况下使用 std::istream 是一件好事情(商标)。 - CB Bailey
2
@Charles:如果我告诉你,在点击“提交”之前,我做了完全相反的更改,你会相信我吗?我个人更喜欢更“统一”的标准库。C++标准库是“有机增长”的典范。 - Matthieu M.
2
@Charles:我绝对认为iostreams和string没有耦合是错误的。我的意思是,iostream在基本层面上依赖于操作字符串。减少依赖是一回事,如果你不是string类,提供与C-string一起使用的成员函数是不可原谅的。 - Puppy
1
@Puppy:我绝对不同意iostream依赖于操作字符串,但我更希望它们能够更紧密地集成。 - Mooing Duck

10
这是一个常见的接口设计问题。使用 cin.getline() 是一种自然的请求方式,但为了避免使流代码依赖于 <string>,就不能提供 cin.getline(std::string&) 函数。只有在引入字符串后,才能添加自由的 getline(cin, s)。对于 char* 来说没有什么问题,因为不需要 #include - 这都是语言本身的一部分。
从某些方面来说,当语言允许后续代码向现有类添加更多函数时(例如 Ruby),这很好,但从其他方面来说,去中心化会影响可维护性。当然,还有一个流行的观点是尽量减少成员函数,增加自由函数:我个人认为不应该将其推到极致,以至于使接口不够直观和表达力强,但每个人都有自己的看法。

1
这似乎是唯一一个明确说明为什么这种解耦是有意设计的答案。毕竟,仅仅因为stringiostream更新,并不足以解释为什么后者没有进行改装。我猜在某个时候,这个决定并不那么具有争议性,而拥有一个未使用的string类的开销相对较大。 - Daniel Saner

2
在iostreams库中,getline变量不支持将字符串作为目标,因此字符串库定义了一个支持该功能的变量。

1

是的,现代C++的方法是使用自由函数并输入std::string。

但是IOStream的历史要比std::string长得多(标准版本至少是相同设计的第三个版本),这个历史解释了为什么事情是这样的。

(getline成员的优点是它不意味着动态分配;这种特性有时可能很方便,但可能不足以在从头开始设计中证明其价值)。


-1

Source:https://www.reddit.com/r/learnprogramming/comments/4fx64h/is_there_a_difference_between_cingetline_and/

成员函数cin.getline()适用于C字符串(即char数组),而自由函数std::getline()适用于C++字符串(即std::string)。当学习C++时,您不应该使用C字符串,这意味着您不应该使用cin.getline()。
std::getline()从输入流中读取一个字符串直到某个分隔符。默认情况下,分隔符是'\n',如果您只想传递换行字符,则没有理由指定第三个参数。它不知道也不关心该字符串中包含什么内容,除了检查分隔符之外。如果您想尝试将该字符串解析为整数或浮点值,则可以在从流中读取后执行此操作,但这并不是std::getline()的工作。它只是读取一个字符串。

当完全引用整段内容时,仅提供源链接是不够的。您还应该通过块引用格式来标注引用。 - anothernode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接