Re: [Boost-users] [iostreams] filtering_istream not working as intended..
Hello all, I am running into some odd "quirks" of the filtering_istream in the boost::iostreams library. Perhaps I am just using it wrong, but all code compiles, and does _almost_ what I would expect it to. Example Code: #include <boost/iostreams/tee.hpp> #include <boost/iostreams/invert.hpp> #include <boost/iostreams/device/file.hpp> #include <boost/iostreams/filtering_stream.hpp> #include <iostream> int main() { boost::iostreams::file log_file("sample.txt", std::ios::trunc); boost::iostreams::filtering_istream in; in.push( boost::iostreams::invert(boost::iostreams::tee(log_file)) ) /* this part is optional */ in.push( std::cin ); std::string s; int i; /* step 1 */ getline(std::cin,s); /* note: std::cin as istream passed to getline */ std::cin >> i; std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' ); std::cout << s << std::endl << i << std::endl; /* step 2 */ getline(in,s); /* note: filtering_istream wrapping std::cin passed here */ in >> i; std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' ); std::cout << s << std::endl << i << std::endl; /* I would expect step 1 and step 2 to behave exactly the same (except for the loggin) */ } As documented, I would expect the two input blocks to exhibit the exact same behavior. Unfortunately, on my platform anyway ( gcc 4.3.3 on 64 bit linux ) - and verified by another user ( also on linux 64 bit, gcc 4.4 ) - that the two code blocks not only differ, but differ in odd ways. The filtering_istream blocks on input, and will not resume until *4* EOF characters are sent. If I remove the invert(tee(log_file)) only *2* EOF need to be sent. First off, I do not know why it is blocking (perhaps this is expected from a filtering_istream which expects to read the entire stream to EOF). I have not found this documented anywhere. Either way, the fact that multiple EOF's need to be sent, and the fact that that number differs depending on the pipeline, leads me to think there is either a bug or I am not using something as intended. Thanks for any help! -Michal p.s. My requirements are only to create an istream which sends what is read from standard input to a log file, while still having the input available for processing by the application. Maybe can suggest another way to solve the problem?
mmocny wrote:
boost::iostreams::file log_file("sample.txt", std::ios::trunc); boost::iostreams::filtering_istream in; in.push( boost::iostreams::invert(boost::iostreams::tee(log_file)) ) /* this part is optional */ in.push( std::cin ); std::string s; int i; [snip] /* step 2 */ getline(in,s); /* note: filtering_istream wrapping std::cin passed here */ in >> i; std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' ); std::cout << s << std::endl << i << std::endl; [snip] The filtering_istream blocks on input, and will not resume until *4* EOF characters are sent. If I remove the invert(tee(log_file)) only *2* EOF need to be sent.
The problem comes from the buffering, which is in multiple places. Neglecting the invert(tee(file)) for the moment, disabling buffering when push()-ing std::cin like this: filtering_istream in; in.push(std::cin, 0); //Note the "0 buffer size" passed here causes the rest of your example program to function properly. Buffering around the invert(tee(file)) can be made similarly: in.push(invert(tee(log_file)), 0); But this not enough, because of the way invert works: When reading from it, it first fills a buffer, and then flushes that buffer to the sink. What happens here is that not enough input can be read for filling the buffer, and this step thus blocks. I'm not sure this is efficient, but setting a buffer size of 1 on the "invert" seems to work. (Annoyingly, the invert() function does not take a buffer size parameter, so I have to explicitely construct an inverse in what follows). Summing up, constructing the filtering_istream as follows "works": namespace bio = boost::iostreams; bio::file log_file("deleteme.txt", std::ios::trunc); bio::filtering_istream in; in.push(bio::inverse<bio::tee_filter<bio::file> >(bio::tee(log_file), 1), 0); in.push(std::cin, 0); HTH, Éric Malenfant
participants (2)
-
Eric MALENFANT
-
mmocny