ostringstream at beginning

Consider an ostringstream which uses the default mode (overwrite at beginning).

Here, a value output to the stream should overwrite the stream at the beginning.

I find this happens only for the 1st value output to the stream; subsequent values output to the stream are appended.

Why is this happening?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void atstart()
{
    /// write at beginning
    ostringstream oss {"Label: "};

    cout << oss.str() << endl;		/// "Label: "

    oss << "val";
    cout << oss.str() << endl;          /// "valel: "

    oss << "Exa";
    cout << oss.str() << endl;          /// "valExa "

    oss << "one";
    cout << oss.str() << endl;          /// "valExaone"

    oss << " two" << " three";          /// "valExaone two three"
    cout << oss.str() << endl;

    cout << endl;
}


Thanks.
Here's the program:

http://cpp.sh/5fcqo
> Why is this happening?

Each output operation advances the put position of the stream (by the number of characters that were written).

Check this program out:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <sstream>
#include <iomanip>

void debug_dump( std::ostringstream& stm )
{
    const auto pos = stm.tellp() ;

    std::cout << "      buffer: " << std::quoted( stm.str() ) << '\n'
              << "              " << ' ' << std::string( pos, ' ' ) << "^\n"
              << "put position: " << ' ' << std::string( pos, ' ' ) << pos << "\n\n" ;
}

int main()
{
    std::ostringstream oss {"012345678901234567890"};
    debug_dump(oss) ;

    oss << "val";
    debug_dump(oss) ;

    oss << "Exa";
    debug_dump(oss) ;

    oss << "one";
    debug_dump(oss) ;

    oss << " two" << " three four five";
    debug_dump(oss) ;

    oss.seekp(3) ;
    debug_dump(oss) ;

    oss << "**!!**" ;
    debug_dump(oss) ;

    oss.seekp( +5, std::ios_base::cur  ) ;
    debug_dump(oss) ;

    oss << "##@@##" ;
    debug_dump(oss) ;
}

http://coliru.stacked-crooked.com/a/3b483486d8e5c4f7
It appears that by default the stream pointer is placed at the beginning of the stream after construction. If you want the stream to be positioned at the end of the stream you either need to seek() to the end of the stream or use the ios::ate flag when constructing the stream.
This is correct, and by design. All streams behave this way. Life would be very frustrating if it didn't.

For example:
1
2
3
4
5
int main()
{
  std::cout << "Hello ";
  std::cout << "world!";
}

What do you expect to see on the screen?
 
Hello world!
world!

The text on the left is correct. If all we got was the text on the right, life would suck.

A string stream is no different, in fact, it satisfies its purpose: reuse C++ stream capabilities to compose a string from smaller parts:

   "Hello "  +  name  +  "! I hear you are "  +  age  +  " years old!"

That should immediately look kind of familiar. C++ phrases it like this:

  cout << "Hello " << name << "! I hear you are " << age << " years old!";

That cout can be replaced with any valid output stream. Like a stringstream.

1
2
3
ostringstream ss;
ss << "Hello " << name << "! I hear you are " << age << " years old!";
string s = ss.str();

Don't be confundled by the fact that not all output has to happen in the same statement. You can split it up in multiple lines, as always. The behavior is consistent.

1
2
3
4
5
ostringstream ss;
ss << "Hello ";
// do something else here, like call a function or whatever //
ss << "world!";
string s = ss.str();

Being consistent, we can rightly expect s to have the value "Hello world!".

Hope this helps.
I see your point.

I had thought that the default mode for a stringstream ("at start") applied for _every_ output to the stream.

However, the mode evidently works only to _initially_ set the internal pointer (that indicates the current position of the stream) to the desired position.

An explicit mode::ate sets the pointer to the _end_ of the stream's initialized content.
The default mode sets the pointer to the _start_ of the stream's initialized content.

Thereafter, each successive output resets the current pointer to the end of the stream's content.

The default mode, then, would be useful to _overwrite_ the initialized content of a stringstream.

For instance, a stringstream could be constructed with an initial prompt and the default mode. The user's input would then overwrite the initial prompt.

1
2
3
4
5
6
7
8
9
10
11
12
13
void atstart()
{
    /// write at beginning
    ostringstream bday {"dd/mm/yy"};

    cout << bday.str() << endl;         /// dd/mm/yy

    bday << "20/12/05";

    cout << bday.str() << endl;         /// 20/12/05

    cout << endl;
}
> Thereafter, each successive output resets the current pointer to the end of the stream's content.

No.

Thereafter, each output operation advances the put position of the stream by the number of characters that were written. The stream buffer content after that point, if any, would remain and would be overwritten by the next output operation without a prior seekp. See the last part of the output of the program posted earlier (after oss.seekp(3) ;).

The exception to the above rule is when the open mode is std::ios_base::app.
In this case, any write operation is performed after a seek to the end of stream (output is performed after resetting the current pointer to the end of the stream's content.)
Thanks for the clarification. I stand corrected.
LOL, I keep seeing your response on the general forum page and laughing. I wanna say something like

"Sit down son! At ease!"

or

"Now go, young grasshopper, and fly!"

or

"Go and sin no more, brother."

or some other silliness. But seriously, I'm glad we were able to help. You'll find yourself doing the same before too long. Enjoy the learning journeying, dude!
Topic archived. No new replies allowed.