ostringstream

S

sagenaut

I am puzzled for the following code:

ostringstream oss;
oss << "this is a test";
const char* test = oss.str().c_str();

the "test" get a empty c-string instead of "this is a test". But if I
do this:

string mystr = oss.str();
const char* test = mystr.c_str();

then the "test" get the "this is a test" c-string.

Why?

I run this code in VC++2025

Thanks in advance.
 
N

Noah Roberts

I am puzzled for the following code:

ostringstream oss;
oss << "this is a test";
const char* test = oss.str().c_str();

The above code assigns test to be a pointer to data that is temporary.
Both the return of c_str() and str() are temporary structures. You
actually need to be smarter about it.
the "test" get a empty c-string instead of "this is a test". But if I
do this:

string mystr = oss.str();
const char* test = mystr.c_str();

This also assigns test to a temporary construct but since the return of
str() has been copied, it just happens to still point at data that
continues to exist (c_str() must be returning a pointer to data within
the string object).

What you really want is something like this:

string mystr = oss.str();
char const* test = new char[mystr.size() + 1];
strcpy(test, mystr.c_str());

.....

delete test;

What you really, really want is to not mess with char * at all. As
such, you'd continue to use std::string or go with std::vector:

string my_str = oss.str();
vector<char const*> test(mystr.size() + 1);
strcpy(&test[0], mystr.c_str());
 
A

Alf P. Steinbach

* (e-mail address removed):
I am puzzled for the following code:

ostringstream oss;
oss << "this is a test";
const char* test = oss.str().c_str();

the "test" get a empty c-string instead of "this is a test". But if I
do this:

string mystr = oss.str();
const char* test = mystr.c_str();

then the "test" get the "this is a test" c-string.

In the first case you a pointer to the c_str() of std::string temporary that no
longer exists afterwards. It will not be a nullpointer, but it is not guaranteed
to be a pointer to an empty string, or to anything in particular, even though it
was a pointer to a string originally. It's just an /invalid/ pointer, a pointer
to now deallocated and possibly reused memory.

In the second case the std::string object still exists after the initialization
of 'test', and it hasn't been modified, so the pointer is till valid.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Noah Roberts:
The above code assigns test to be a pointer to data that is temporary.
Both the return of c_str() and str() are temporary structures. You
actually need to be smarter about it.
Right.



This also assigns test to a temporary construct but since the return of
str() has been copied, it just happens to still point at data that
continues to exist (c_str() must be returning a pointer to data within
the string object).

No, sorry, there's no temporary assigned to.

However, the 'test' pointer is only valid for the scope of 'mystr', and it's
only valid as long as 'mystr' isn't assigned to or pushe_back'ed to or something
else that may cause it to reallocate its buffer.

What you really want is something like this:

string mystr = oss.str();
char const* test = new char[mystr.size() + 1];
strcpy(test, mystr.c_str());

....

delete test;

This is unnecessary.

The 'mystr' provides the needed allocation, copying and deallocation.

What you really, really want is to not mess with char * at all.

Agreed. :)

As such, you'd continue to use std::string or go with std::vector:

string my_str = oss.str();
vector<char const*> test(mystr.size() + 1);
strcpy(&test[0], mystr.c_str());

Uh, that's really bad and is clearly not what you meant to write.


Cheers & hth.,

- Alf
 
N

Noah Roberts

Noah said:
I am puzzled for the following code:

ostringstream oss;
oss << "this is a test";
const char* test = oss.str().c_str();

The above code assigns test to be a pointer to data that is temporary.
Both the return of c_str() and str() are temporary structures. You
actually need to be smarter about it.
the "test" get a empty c-string instead of "this is a test". But if I
do this:

string mystr = oss.str();
const char* test = mystr.c_str();

This also assigns test to a temporary construct but since the return of
str() has been copied, it just happens to still point at data that
continues to exist (c_str() must be returning a pointer to data within
the string object).

What you really want is something like this:

string mystr = oss.str();
char const* test = new char[mystr.size() + 1];

oops! That can't be const.
strcpy(test, mystr.c_str());

....

delete test;

What you really, really want is to not mess with char * at all. As
such, you'd continue to use std::string or go with std::vector:

string my_str = oss.str();
vector<char const*> test(mystr.size() + 1);

oops. this should be vector<char>.

pretty tired this morning.
strcpy(&test[0], mystr.c_str());
 
J

Jorgen Grahn

Wow! A time machine! But it seems it still cannot figure out a simple case
of undefined behaviour!

In 2022, Microsoft will add an option to the compiler to go back in
time and post a question on comp.lang.c++ at its peak. That will be
easier to implement (and faster too; the answers will already be in
Google's archive).

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top