- 主题:[求助]又是烦人的cin,linux和win10下结果还不一样!
- 从键盘向两个vector vec和vec2填充字符串的程序:
 
 #include <iostream> // For standard streams
 #include <string>
 #include <vector>
 #include <algorithm>
 #include <iterator>
 
 using namespace std;
 
 static void cin_state(void)
 {
 cout << "[fail,eof,bad]: ["
 << cin.fail() << cin.eof() << cin.bad()
 << "], state-good: " << cin.good() << endl;
 }
 
 static void cin_clear(void)
 {
 cout << "\n=>before cin.clear()";
 cin_state();
 cin.clear();
 cout << "  after cin.clear()";
 cin_state();
 }
 
 int main(void)
 {
 std::vector<std::string> vec, vec2;
 std::copy(std::istream_iterator<std::string> {std::cin},
 std::istream_iterator<std::string>{},
 std::back_inserter(vec));
 std::copy(std::cbegin(vec),
 std::cend(vec),
 std::ostream_iterator<std::string>{std::cout, " "});
 
 cin_clear();
 
 std::copy(std::istream_iterator<std::string> {std::cin},
 std::istream_iterator<std::string>{},
 std::back_inserter(vec2));
 
 return 0;
 }
 
 Win10+vs2019没有问题
 
 
 Linux下vec2根本就没有机会输入,好像车子挂不上档,即使我增加std::cin.ignore()也没有用:
 $  Snippets ./a.out
 akdf kdfj ksdj fksdfj dsf
 akdf kdfj ksdj fksdfj dsf
 =>before cin.clear()[fail,eof,bad]: [110], state-good: 0
 after cin.clear()[fail,eof,bad]: [000], state-good: 1
 $  Snippets
 --
 修改:ActiveIon FROM 61.149.156.*
 FROM 61.149.156.*
 
- 补上win10+vs2019的运行结果(正常):
 
 C:\Users\92787\source\repos\books_sourcecode\Using_STL>test
 skdjfskjfdlkdsaj lkjlks jd fkj ksdjf kdsjfksj kkdsjfkdsj fkj dsfkjkds fjkdsfj kjdsf kdsfj
 ^Z
 skdjfskjfdlkdsaj lkjlks jd fkj ksdjf kdsjfksj kkdsjfkdsj fkj dsfkjkds fjkdsfj kjdsf kdsfj
 =>before cin.clear()[fail,eof,bad]: [110], state-good: 0
 after cin.clear()[fail,eof,bad]: [000], state-good: 1
 sdf dskfj kdsfj djf kdfj kdfj kdfj
 ^Z
 
 C:\Users\92787\source\repos\books_sourcecode\Using_STL>
 --
 FROM 61.149.156.*
 
- 这对我来说,太难了。 哭笑不得。
 anyway,谢谢。
 
 【 在 yytree 的大作中提到: 】
 : Checking C runtime library
 : Disassemble your code
 :
 --
 FROM 61.149.156.*
 
- 那再想用这个cin输入,咋办?cin是单例吧。
 【 在 ilovecpp 的大作中提到: 】
 : linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
 --
 FROM 61.149.156.*
 
- 网上搜索到这段话,但不知道具体如何重新连接tty:
 
 在无效输入后可以恢复状态:未能根据预期类型解析输入,只需设置 std:: ios_base::failbit ,这可以是 clear() . 由于不会删除导致问题的字符,因此您可能需要摆脱它(例如使用 ignore() )或以不同方式对数据进行parae .
 
 虽然EOF也只是一个标志( std::ios_base::eofbit )清除它一般不会从已经到达流的末尾恢复 . 特定流可以具有继续读取的方式,但是在流指示符结束之后控制台很可能被断开(例如,Ctrl-D或Ctrl-Z) . 根据系统,可以创建到控制台的新连接,例如,通过打开文件流到 /dev/tty .
 
 如果您确实想使用控制字符来指示特殊处理,请使用 tcgetattr() 和 tcsetattr() 将流设置为非规范模式 . 完成此操作后,可以看到输入的所有字符,并且可以在自定义流缓冲区中进行处理 . 我不知道如何在其他系统上做类似的事情 .
 【 在 ilovecpp 的大作中提到: 】
 : linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
 --
 FROM 61.149.156.*
 
- 感谢大家。终于搞定了
 
 #include <iostream> // For standard streams
 #include <vector>
 #include <string>
 #include <algorithm>
 #include <iterator>
 
 static void cin_state(void)
 {
 std::cout << "[fail,eof,bad]: ["
 << std::cin.fail() << std::cin.eof() << std::cin.bad()
 << "], state-good: " << std::cin.good() << std::endl;
 }
 
 
 static void cin_clear(void)
 {
 std::cout<<"\n=>before cin.clear()";
 cin_state();
 
 std::cin.clear();
 
 std::cout << "   after cin.clear()";
 cin_state();
 }
 
 
 #include <cstdio>
 #include <fstream>
 int main(void)
 {
 std::vector<std::string> vec;
 std::copy(std::istream_iterator<std::string>{std::cin},
 std::istream_iterator<std::string>{},
 std::back_inserter(vec));
 std::copy(std::cbegin(vec),
 std::cend(vec),
 std::ostream_iterator<std::string>{std::cout, " "});
 std::cout << std::endl;
 
 /****
 * 和Windows不同, Linux的EOF后,std::cin就不能复活了
 * 因为已经和/dev/stdin文件断开了连接,只能使用ifstream重新连接。
 * 而Windows的std::cin接收到EOF以后,可是使用cin.clear()重新复活
 *
 * 当然,Win和Linux如果发生failbit,都可以通过clear()重新复活,
 * 虽然往往需要再调用ignore()来剔除缓冲区中的一些多余的字符。
 */
 std::vector<std::string> vec2;
 #ifdef __unix__
 std::ifstream fin("/dev/stdin");
 std::istream_iterator<std::string> iit{fin};
 #endif
 #ifdef WIN32
 cin_clear();
 std::istream_iterator<std::string> iit{std::cin};
 #endif
 std::copy(iit,
 std::istream_iterator<std::string>{},
 std::back_inserter(vec2));
 std::copy(std::begin(vec2),
 std::end(vec2),
 std::ostream_iterator<std::string>{std::cout, " "});
 std::cout << std::endl;
 
 return 0;
 }
 /*
 *
 $ ./a.out
 dkfj  k                 kdfj sf dsalaskd jf
 dkfj k kdfj sf dsalaskd jf
 aa bb cc dd ee ff
 aa bb cc dd ee ff
 $
 *
 */
 
 
 【 在 ilovecpp 的大作中提到: 】
 : linux下eof就是eof,你再怎么clear也不可能从cin读到数据了。
 --
 FROM 61.149.156.*
 
- ilovecpp的建议超赞! 感谢。 
 
 按照这个思路,我的代码改为:
 
 
 
 #include <string>
 #include <iostream>
 #include <sstream>
 #include <vector>
 #include <iterator>
 using namespace std;
 
 template <typename T>
 void cin_fill(back_insert_iterator<T> bit)
 {
 string line;
 while (true)
 {
 getline(cin, line);
 if (!line.empty())
 {
 istringstream ss{line};
 for (;;)
 {
 typename T::value_type n;
 ss >> n;
 if (!ss)
 break;
 bit=n;
 }
 } else break;
 }
 }
 #include <algorithm>
 int main(void)
 {
 {
 vector<int> vec;
 cin_fill(back_inserter(vec));
 std::copy(std::cbegin(vec), std::cend(vec), std::ostream_iterator<int>{std::cout, " "});
 std::cout << std::endl;
 }
 {
 vector<std::string> vec;
 cin_fill(back_inserter(vec));
 std::copy(std::cbegin(vec), std::cend(vec), std::ostream_iterator<std::string>{std::cout, " "});
 std::cout << std::endl;
 }
 
 return 0;
 }
 /***
 12 34 56
 78 q 90
 
 12 34 56 78
 ^C
 */
 
 
 【 在 ilovecpp 的大作中提到: 】
 : 不建议把输入格式设计成这样。就像我前面说的,linux文件里没有EOF字符,你这样搞,如果输入是从文件重定向的就根本没法输入了。
 : 比如,你可以用回车表示一组数据结束:
 : string line;
 : ...................
 --
 修改:ActiveIon FROM 111.201.151.*
 FROM 61.149.156.*
 
- 是可以的,只是不应该这么设计。
 
 其实一个流需要重复使用,就不应该发送EOF结束符号,而应该向ilovecpp说的那样使用“空行”来结束一次输入。linux不能复活EOF,也是这么考虑的,是正确的思路。win使用clear()来复活EOF我觉得是不对的。
 
 linux这个行为可以扩展到socket中,socket关闭后也是不能复活的,虽然socket关闭后,read系统调用返回的不是EOF(其实为0xFF)而是0, 但道理是相通的:关闭的流就不应该被复活。
 
 
 【 在 here080 的大作中提到: 】
 : 可不可以不用宏?可不可以全部都使用ifstream来重新连接?
 :
 --
 FROM 61.149.156.*