The two functions foo() and bar() are trying to do the same thing. foo
doesn't work but bar does. My question "Is bar a leagal function or is
it treading into the undefined behaviour and I'm simply getting away
with it"? I have tried the code both in VC 6 and VC 2005. Both exhibit
the same behaviour.

As long as I use the ostringstream::str() function as the first output
variable it seems to work. As soon as it appears in a different
location, the code will crash.

#include "stdafx.h"
#include <string>
#include <sstream>

using namespace std;

std::string SomeFunc( const std::string &str )
{
// Iterate through string and calculate a checksum
return " checksum ";
}

void foo()
{
const char stx = '\2';
const char etx = '\3';

std::ostringstream os;

os << stx
<< "One"
<< SomeFunc(os.str().substr(1)) // crashes here
<< etx;

std::string done = os.str();
}

void bar()
{
const char stx = '\2';
const char etx = '\3';

std::ostringstream os;

os << stx
<< "One";
os << SomeFunc(os.str().substr(1)) // works but why?
<< etx;

std::string done = os.str();
}

int main(int argc, char * argv[])
{
argc; argv;

foo(); // doesn't work
bar(); // works fine
return 0;
}

Re: correct usage of ostringstream by Doug

Doug
Wed Jul 25 11:52:34 CDT 2007

On Wed, 25 Jul 2007 09:03:32 -0700, mzdude <jsanga@cox.net> wrote:

>The two functions foo() and bar() are trying to do the same thing. foo
>doesn't work but bar does. My question "Is bar a leagal function or is
>it treading into the undefined behaviour and I'm simply getting away
>with it"? I have tried the code both in VC 6 and VC 2005. Both exhibit
>the same behaviour.
>
>As long as I use the ostringstream::str() function as the first output
>variable it seems to work. As soon as it appears in a different
>location, the code will crash.
>
>#include "stdafx.h"
>#include <string>
>#include <sstream>
>
>using namespace std;
>
>std::string SomeFunc( const std::string &str )
>{
> // Iterate through string and calculate a checksum
> return " checksum ";
>}
>
>void foo()
>{
> const char stx = '\2';
> const char etx = '\3';
>
> std::ostringstream os;
>
> os << stx
> << "One"
> << SomeFunc(os.str().substr(1)) // crashes here
> << etx;
>
> std::string done = os.str();
>}

In the most tenuous sense, it's well-defined, but the output is unspecified
due to the many possible orders in which the arguments can be evaluated.
You have to realize that the substr expression could be evaluated before
"os << stx" is executed, and if this is done in foo(), it will cause substr
to throw an exception.

>void bar()
>{
> const char stx = '\2';
> const char etx = '\3';
>
> std::ostringstream os;
>
> os << stx
> << "One";
> os << SomeFunc(os.str().substr(1)) // works but why?
> << etx;
>
> std::string done = os.str();
>}

This works because os definitely contains data when you call substr, and
the output is what you expect because the evaluation of etx can't affect
os.str() even if evaluated before that argument. I'd still rewrite it like
this:

os << ...
std::string s = os.str().substr(1);
os << ...

>int main(int argc, char * argv[])
>{
> argc; argv;

Just write "int main()".

> foo(); // doesn't work
> bar(); // works fine
> return 0;
>}

Wrapping foo like this may shed some light on the problem:

try
{
foo();
}
catch(std::exception& ex)
{
std::cout << ex.what() << '\n';
}

--
Doug Harrison
Visual C++ MVP

Re: correct usage of ostringstream by Igor

Igor
Wed Jul 25 12:02:27 CDT 2007

mzdude <jsanga@cox.net> wrote:
> The two functions foo() and bar() are trying to do the same thing. foo
> doesn't work but bar does. My question "Is bar a leagal function or is
> it treading into the undefined behaviour and I'm simply getting away
> with it"? I have tried the code both in VC 6 and VC 2005. Both exhibit
> the same behaviour.
>
> As long as I use the ostringstream::str() function as the first output
> variable it seems to work. As soon as it appears in a different
> location, the code will crash.
>
> void foo()
> {
> const char stx = '\2';
> const char etx = '\3';
>
> std::ostringstream os;
>
> os << stx
> << "One"
> << SomeFunc(os.str().substr(1)) // crashes here
> << etx;

A compiler can evaluate subexpressions of an expression in any order,
subject to certain limitations. In particular, it can evaluate
os.str().substr(1) before os << stx. Which is what it apparently does in
this case: by the time substr(1) is called, os.str() is still an empty
string, and substr() throws out_of_range exception.

>
> std::string done = os.str();
> }
>
> void bar()
> {
> const char stx = '\2';
> const char etx = '\3';
>
> std::ostringstream os;
>
> os << stx
> << "One";
> os << SomeFunc(os.str().substr(1)) // works but why?
> << etx;

Semicolon introduces a sequence point: os << stx << "One" is always
executed before os.str().substr(1), so os.str() cannot be empty.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925