By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,830 Members | 1,722 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,830 IT Pros & Developers. It's quick & easy.

I am mystified... need help with STL.

P: n/a
Hi all,

I'm having some trouble understanding the behavior of std::ostringstream.
(I'm using Visual Studio .Net & STL port 4.5.3). I'll appreciate if someone
can give me a little explanation of this behavior and how it is possible...

Here's my code

//////////////////////////
#include <stdio.h>
#include <ostream>

void func( const char* s )
{
printf( "func: [%u], [%s]\n", s, s );
}

void main( void )
{
std::ostringstream stream;
stream << "Hello World";
const char* s = stream.str().c_str();
printf( "main: [%u], [%s]\n", s, s );
func( stream.str().c_str() );
}
////////////////////////////////

And here's my result:

main: [3290280], []
func: [3290280], [Hello World]

Thankx a lot!
Ben Thomas.
Jul 19 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Ben Thomas wrote:
Hi all,

I'm having some trouble understanding the behavior of std::ostringstream.
(I'm using Visual Studio .Net & STL port 4.5.3). I'll appreciate if someone
can give me a little explanation of this behavior and how it is possible...

Here's my code

//////////////////////////
#include <stdio.h>
#include <ostream>
What about <sstream>?

void func( const char* s )
{
printf( "func: [%u], [%s]\n", s, s );
This invokes undefined behavior. The %u format specifier is for unsigned
ints only. You are passing it a const char *. This is a good example of
why you should not use printf or any function or language construct that
defeats type-checking.
}

void main( void )
main returns int. void is not and never has been an acceptable return
type for main.
{
std::ostringstream stream;
stream << "Hello World";
const char* s = stream.str().c_str();
My best guess is that ostringstream::str() returns by value (strangely,
I can't find this information in either Stroustrup or Josuttis). That
means you get a temporary std::string, which you then invoke c_str() on.
However, the temporary goes out of scope after this statement completes,
and the pointer returned from c_str() is no longer valid. Try this instead:

std::string tmp = stream.str();
const char* s = tmp.c_str();
printf( "main: [%u], [%s]\n", s, s );
Undefined behavior again.
func( stream.str().c_str() );


In this case, the same thing happens except that the temporary does not
go out of scope until the function completes.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #2

P: n/a

"Kevin Goodsell" <us*********************@neverbox.com> wrote in message news:AA68b.8848
printf( "func: [%u], [%s]\n", s, s );


This invokes undefined behavior. The %u format specifier is for unsigned
ints only. You are passing it a const char *. This is a good example of
why you should not use printf or any function or language construct that
defeats type-checking.


Yes, if he wants to inspect the pointer, the way to do it is:
printf("func [%p],[%s]\n", (void*)s, s);

Jul 19 '05 #3

P: n/a
Ron Natalie wrote:
"Kevin Goodsell" <us*********************@neverbox.com> wrote in
message news:AA68b.8848
printf( "func: [%u], [%s]\n", s, s );


This invokes undefined behavior. The %u format specifier is for
unsigned ints only. You are passing it a const char *. This is a
good example of why you should not use printf or any function or
language construct that defeats type-checking.


Yes, if he wants to inspect the pointer, the way to do it is:
printf("func [%p],[%s]\n", (void*)s, s);


To be a complete nitpicker, the C++ way to do it is:
std::cout << "main: [" << static_cast<const void*>(s) << "], [" << s <<
"]" << std::endl;

Or even more nitpicky, we should forget char* altogether, std::string should
be good enough for us C++ types:
std::cout << "main: [" << stream.str() << "]" << std::endl;

^_^

--
Unforgiven

"Most people make generalisations"
Freek de Jonge

Jul 19 '05 #4

P: n/a
Thankx for the answer!

Okay, I have fixed the problem with displaying the pointers value and change
#include<ostream> with #include<sstream> and return 0 in the main function
and it's the same behavior! :)

The solution of a temp variable works! I too first though that it was a
scope problem, that's why I displayed the pointer value. Yet, they are the
same, so scope seems to be okay, only that it's empty in one call and not in
the other. Also, I don't know if there's a difference in scope between the
two kind of call... I have tryed to write a class that reproduce the same
kind of behavior but wasn't able to do so... maybe it's in the many level of
template with STL, but how can you make your class act differently between
this

const char* s = stream.str().c_str();

and this

func( stream.str().c_str() ); // void func( const char* s );

I just can't make sense of it... maybe the problem is elsewhere after all.
Ben Thomas.

"Ron Natalie" <ro*@sensor.com> wrote in message
news:3f***********************@news.newshosting.co m...

"Kevin Goodsell" <us*********************@neverbox.com> wrote in message

news:AA68b.8848
printf( "func: [%u], [%s]\n", s, s );


This invokes undefined behavior. The %u format specifier is for unsigned
ints only. You are passing it a const char *. This is a good example of
why you should not use printf or any function or language construct that
defeats type-checking.


Yes, if he wants to inspect the pointer, the way to do it is:
printf("func [%p],[%s]\n", (void*)s, s);

Jul 19 '05 #5

P: n/a
Ben Thomas wrote:
Thankx for the answer!
Please don't top-post. Re-read section 5 of the FAQ for posting guidelines.

http://www.parashift.com/c++-faq-lite/

Okay, I have fixed the problem with displaying the pointers value and change
#include<ostream> with #include<sstream> and return 0 in the main function
and it's the same behavior! :)

The solution of a temp variable works! I too first though that it was a
scope problem, that's why I displayed the pointer value. Yet, they are the
same,
This proves absolutely nothing.
so scope seems to be okay,
Bad conclusion.
only that it's empty in one call and not in
the other.
It's undefined in one call, and not in the other.
Also, I don't know if there's a difference in scope between the
two kind of call... I have tryed to write a class that reproduce the same
kind of behavior but wasn't able to do so... maybe it's in the many level of
template with STL, but how can you make your class act differently between
this

const char* s = stream.str().c_str();
OK, I'll try to explain again (but I suspect you need to look up
"temporaries" or "temporary objects" in your C++ book).

stream.str() returns by value. This means that the result is copied into
a "temporary object". Now, the ruled for temporary objects state that
they go out of scope at the end of the full expression in which they are
created. A full expression is an expression that is not a sub-expression
of any larger expression, therefore the full expression in this
particular case is the entire statement, minus the semi-colon. That
means that the temporary std::string object containing the result of
stream::str() is GONE once this statement completes. It no longer exists.

Since the pointer returned from std::string::c_str() ceases to be valid
when the std::string is modified or destroyed, your 's' pointer stops
being valid as soon as you initialize it.

and this

func( stream.str().c_str() ); // void func( const char* s );
In this case, the full expression includes the function call. The
function call uses the pointer while it's still valid. As soon as the
function completes, the temporary std::string object goes out of scope
and the pointer is no longer valid - but that's OK this time because you
haven't saved it anywhere.

I just can't make sense of it... maybe the problem is elsewhere after all.


I'm quite sure this IS the problem. I've verified my assumption about
the return type of std::ostringstream::str() by checking the standard.
What you are doing is roughly equivalent to this:

#include <iostream>
#include <cstring>

using namespace std;

class Stupid
{
char *str;
public:
Stupid() : str(new char[20]) { strcpy(str, "this is stupid");
cout << "Constructing a Stupid object" << endl; }
~Stupid() { delete [] str;
cout << "Destroying a Stupid object"
" (and releasing memory)" << endl; }
char *GetPtr() { return str; }
};

int main()
{
char *s = Stupid().GetPtr();

cout << "The string pointed to by s is:\n" << s << endl;

return 0;
}

If you can't see why this is horribly broken, try running it. The object
dies and releases its memory before you even have a chance to use 's'.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #6

P: n/a
So, Ben, if you really want your code to work, just make a few adjustments:

#include <stdio.h>
#include <sstream>
#include <string>

void func( const char* s )
{
printf( "func: [%p], [%s]\n", s, s );
}

void main( void )
{
std::ostringstream stream;
stream << "Hello World";
std::string s = stream.str();
printf( "main: [%p], [%s]\n", s.c_str(), s.c_str() );
func( stream.str().c_str() );
}

That way, you *copy* the temporary object to a new (non-temporary) one, and
it's valid when you call your func function.

Maybe this should help you understand std::ostringstream a little better :-)

BR,
Peter Kragh
Jul 19 '05 #7

P: n/a
Peter Kragh wrote:
So, Ben, if you really want your code to work, just make a few adjustments:

#include <stdio.h>
Deprecated.
#include <sstream>
#include <string>

void func( const char* s )
{
printf( "func: [%p], [%s]\n", s, s );
This is an error, as has already been discussed in this thread. %p only
accepts void*.
}

void main( void )
main must return int. This is required by the C++ standard.
{
std::ostringstream stream;
stream << "Hello World";
std::string s = stream.str();
printf( "main: [%p], [%s]\n", s.c_str(), s.c_str() );
Same error.
func( stream.str().c_str() );
}

That way, you *copy* the temporary object to a new (non-temporary) one, and
it's valid when you call your func function.

Maybe this should help you understand std::ostringstream a little better :-)


-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.