Difference between modifying and non-modifying putback() - c++

The question comes from https://en.cppreference.com/w/cpp/io/basic_istream/putback, the example code.
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s2("Hello, world"); // input-only stream
s2.get();
if (s2.putback('Y')) // cannot modify input-only buffer
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
s2.clear();
if (s2.putback('H')) // non-modifying putback
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
}
Why s2.putback('Y') fails but s2.putback('H') succeed? Isn't the latter also an operation to modify the input-only stream buffer?
Also, I find something confusing while doing some experiments.
I add 1 line code compared to the sample above and the second results fails.. Why is it?
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s2("Hello, world"); // input-only stream
s2.get();
if (s2.putback('Y')) // cannot modify input-only buffer
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
std::cout << s2.rdbuf() << '\n'; //1 line code added
s2.clear();
if (s2.putback('H')) // non-modifying putback
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
}

Why s2.putback('Y') fails but s2.putback('H') succeed? Isn't the latter also an operation to modify the input-only stream buffer?
The invocation s2.putback('H') potentially modifies the buffer, but in this case, it does not, because the data already start with an 'H'.
You can exemplify the behavior like this:
s2.clear();
assert(s2.putback('H')); // Ok, replacing 'H' with 'H' doesn't change anything
assert(!s2.putback('Z')); // Can't modify.

You can read further the behavior of sputbackc.
If a putback position is available in the get area (gptr() > eback()), and the character c is equal to the character one position to the left of gptr() (as determined by Traits::eq(c, gptr()[-1]), then simply decrements the next pointer (gptr()).
So in the case of s2.putback('H'), only the next pointer is decremented. The buffer is not changed.
Answer to your edit: basic_ostream& operator<<( std::basic_streambuf<CharT, Traits>* sb); extracts the characters maintained by sb, so after std::cout << s2.rdbuf() << '\n'; the next pointer points to the end of the buffer, which causes s2.putback('H') to fail.

Related

Postpone standard output in the end

Many warning messages (via std::cout) might be printed out during the process. Is there a way to postpone the printing of the warning messaged in the end of the program? There are huge amount of the processing information will be printed. I'm planing to have all the warnings together in the end rather than scattered around.
More background:
code is already there.
there are about 50 warning messages within the code (in case if there is some sort of delay( ) function, I don't want to add 50 times, would be nice if there is an globally delaye/postpone function for stand output)
Thanks
One way to do it is to send everything to a stringstream, and then print at the end.
For example:
#include <iostream>
#include <sstream>
int main(){
int i = 5, j = 4;
std::stringstream ss;
std::cout << i * j << std::endl;
ss << "success" << std::endl;
std::cout << j + i * i + j << std::endl;
ss << "failure" << std::endl;
std::cout << ss.str() << std::endl;
return 0;
}
Output:
20
33
success
failure
If you're just trying to delay all printing of std::cout what you can do is redirect standard out to a string stream that acts as a buffer. It's pretty simple and avoids all of the dup, dup2, and piping stuff that one might be inclined to try.
#include <sstream>
// Make a buffer for all of your output
std::stringstream buffer;
// Copy std::cout since we're going to replace it temporarily
std::streambuf normal_cout = std::cout.rdbuf();
// Replace std::cout with your bufffer
std::cout.rdbuf(buffer.rdbuf());
// Now your program runs and does its thing writing to std::cout
std::cout << "Additional errors or details" << std::endl;
// Now restore std::cout
std::cout.rdbuf(normal_cout);
// Print the stuff you buffered
std::cout << buffer.str() << std::endl;
Also in the future, you should really use a buffer for errors from the start OR at a minimum write errors and logging to std::cerr so that your normal runtime print outs aren't cluttered with errors.

putback fails for stringstream while adding extra char

I have following code snippet to modify the stringstream such that it will have additional one char infront. But, i couldn't get the expected result.
void modifyStream(std::istream& s1)
{
if (s1.putback('Y'))
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
}
int main(int argc, const char * argv[])
{
const char* str = "Hello, world";
std::stringstream s1(str); // IO stream
modifyStream(s1);
return 0;
}
Output: putback failed
But, i am expecting the output of "YHello, world".
Can someone help to resolve this?
There is a misunderstanding about the putback method in your code: Its purpose is not to prepend data to the stream but to replace one already extracted character with another (you do not add anything, you replace an old character with something new). This is a bit more understandable by reading the documentation of sputbackc which is called by putback.
Example (from encppreference):
std::stringstream s1("Hello, world"); // IO stream
s1.get();
if (s1.putback('Y')) // modifies the buffer
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
Output:
Yello, world
The call s1.putback('Y') puts the character 'Y' back at the place of the last extracted character (in this case 'H').

C++ Order of Output

I have a statement like such that is meant to output what the function returns.
std::cout<<"result: " << calculateAvg(someArray, size) << std::endl;
The function however, outputs things itself before it returns the value. Is there a way for me to print out what is returned on that line, instead of after everything that is printed by the function?
Is there a way for me to print out what is returned on that line, instead of after everything that is printed by the function?
No. The function has to run before it can return something. This means any output the function outputs will come before the output of the functions' return value.
You can redirect std::cout to a buffer (see this post), call the function, redirect back, print result and then print the buffer:
#include <iostream>
#include <sstream>
#include <string>
std::string myFunc() {
std::cout << "print inside myFunc" << std::endl;
return "string returned from myFunc";
}
int main() {
std::stringstream print_inside;
std::streambuf * old = std::cout.rdbuf(print_inside.rdbuf());
std::string returned_string = myFunc();
std::cout.rdbuf(old);
std::cout << returned_string << std::endl;
std::cout << print_inside.str() << std::flush; //endl already there
}

how to keep track of the current position in std::stringstream

I am writing a custom logger where I buffer my log messages in a std::stringstream and flush it to a file (std::ofstream) whenever the std::stringstream is big enough(to save some IO latency) . sincestd::stringstream doesn't have a .size() method, I use seekg and tellg :
template <typename T>
MyClass & operator<< (const T& val)
{
boost::unique_lock<boost::mutex> lock(mutexOutput);
output << val; //std::stringstream output;
output.seekg(0, std::ios::end);
if(output.tellg() > 1048576/*1MB*/){
flushLog();
}
return *this;
}
Problem:
It seems to me that, whenever I invoke this method, it uses seekg to start counting the bytes from the beginning all the way to the end and get the size using tellg. I came up with this design to save some IO time in the first place, but: isn't this continuous counting impose a larger cost(if the number of calls to this method is high and log messages are small as in most of the cases)?
is there a better way to do this?
And a side question: is 1MB a good number for buffer size in a normal nowadays computers?
Thank you
You can just use ostringstream::tellp() to get the length of the string. Here's an example lifted from http://en.cppreference.com/w/cpp/io/basic_ostream/tellp.
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream s;
std::cout << s.tellp() << '\n';
s << 'h';
std::cout << s.tellp() << '\n';
s << "ello, world ";
std::cout << s.tellp() << '\n';
s << 3.14 << '\n';
std::cout << s.tellp() << '\n' << s.str();
}
Output:
0
1
13
18
hello, world 3.14

Stringstream read values into double fails?

New Problem
boost::tokenizer<> token(line); tokenizes decimal points! How can I stop this happening?
Previous problem below is now resolved.
I am trying to grab values from a stringstream into a vector of doubles.
std::ifstream filestream;
filestream.open("data.data");
if(filestream.is_open()){
filestream.seekg(0, std::ios::beg);
std::string line;
std::vector<double> particle_state;
particle_state.resize(6);
while(filestream >> line){
boost::tokenizer<> token(line);
int i = -1;
for(boost::tokenizer<>::iterator it=token.begin(); it!=token.end(); ++it){
std::cout << *it << std::endl; // This prints the correct values from the file.
if(i == -1){
// Ommitted code
}
else{
std::stringstream ss(*it);
ss >> particle_state.at(i); // Offending code here?
}
i ++;
}
turbovector3 iPos(particle_state.at(0), particle_state.at(1), particle_state.at(2));
turbovector3 iVel(particle_state.at(3), particle_state.at(4), particle_state.at(5));
// AT THIS POINT: cout produces "(0,0,0)"
std::cout << "ADDING: P=" << iPos << " V=" << iVel << std::endl;
}
filestream.close();
}
Contents of input file:
electron(0,0,0,0,0,0);
proton(1,0,0,0,0,0);
proton(0,1,0,0,0,0);
More on turbovector3:
turbovector3 is a mathematical vector class. (The important thing is that it works - essentially it is a vector with 3 items. It is initialised using the constructor with three doubles.)
Thanks in advance for help!
EDIT Modification of code:
std::stringstream ss(*it);
if(ss.fail()){
std::cout << "FAIL!!!" << std::endl; // never happens
}
else{
std::cout << ss.str() << std::endl; // correct value pops out
}
double me;
ss >> me;
std::cout << "double:" << me << std::endl; // correct value pops out again
particle_state.at(i) = me; // This doesn't work - why?
Do you increment i in the omitted code? If not your else clause never gets called. Try outputting the stringstream buffer contents:
std::cerr << ss.str();
Also check if reading from ss actually fails:
if (ss.fail())
std::cerr << "Error reading from string stream\n";
Solution! I fluked and found this site: Link
The solution is to change the tokenizer to this:
boost::char_delimiters_separator<char> sep(false,"(),;");
boost::tokenizer<> token(line,sep);
Now it works!