lifetime of temp string object

G

Gabor Drasny

Hi all,

Could anyone tell me if the following code is guaranteed to work or not?

#include <string>
#include <iostream>

int main()
{
const char* s = std::string("Hello World").c_str();
std::cout << s << std::endl;
return 0;
}


As I understand the C++ standard the lifetime of the temporary string
object created on the first line of main() ends when the expression
containing it ends (unless an object is initialized as a reference to
the temporary).

If that is true, then the memory s points to is invalidated, since the
temporary string is destructed.

The project I am working on has quite a lot of the above construct, but
I could not bring myself to change all of these, unless I am quite sure
it causes undefined behavior.

Thanks,

Gabor Drasny
 
V

Victor Bazarov

Gabor said:
Could anyone tell me if the following code is guaranteed to work or not?
Not.

#include <string>
#include <iostream>

int main()
{
const char* s = std::string("Hello World").c_str();

This is rather unusual. Why not simply write

const char* s = "Hello World";

???
std::cout << s << std::endl;
return 0;
}


As I understand the C++ standard the lifetime of the temporary string
object created on the first line of main() ends when the expression
containing it ends (unless an object is initialized as a reference to
the temporary).
Yes.

If that is true, then the memory s points to is invalidated, since the
temporary string is destructed.

It is.
The project I am working on has quite a lot of the above construct, but
I could not bring myself to change all of these, unless I am quite sure
it causes undefined behavior.

It does.

V
 
A

Alf P. Steinbach

* Gabor Drasny:
Hi all,

Could anyone tell me if the following code is guaranteed to work or not?

#include <string>
#include <iostream>

int main()
{
const char* s = std::string("Hello World").c_str();
std::cout << s << std::endl;
return 0;
}

Not guaranteed to work:

* Formally you need to also include <ostream>. ;-)

* The temporary std::string ceases to exist after the expression.

The project I am working on has quite a lot of the above construct, but
I could not bring myself to change all of these, unless I am quite sure
it causes undefined behavior.

It's UB.

But note that

int main()
{
std::string const& str = std::string( "Hello, world!" );
const char* s = std.c_str();
std::cout << s << std::endl;
}

is not UB, because that reference to const keeps the temporary, so to speak.
 
A

Adrian

Inline.

Alf P. Steinbach said:
* Gabor Drasny:

Not guaranteed to work:

* Formally you need to also include <ostream>. ;-)

* The temporary std::string ceases to exist after the expression.



It's UB.

But note that

int main()
{
std::string const& str = std::string( "Hello, world!" );
const char* s = std.c_str();
std::cout << s << std::endl;
}

is not UB, because that reference to const keeps the temporary, so to speak.

It might do that in Java or some other language with a GC but not in C++,
this is still UB.
 
M

Mike Wahler

Alf P. Steinbach said:
int main()
{
std::string const& str = std::string( "Hello, world!" );
const char* s = std.c_str();

Typo! Make that:

const char* s = str.c_str();


-Mike
 
V

Victor Bazarov

Alf said:
[...]
But note that

int main()
{
std::string const& str = std::string( "Hello, world!" );
const char* s = std.c_str();

... str.c_str();
std::cout << s << std::endl;
}

is not UB, because that reference to const keeps the temporary, so to speak.

Yes, but why would anybody do that, when it's SO much easier to do

std::string const str("whatever");
const char* s = str.c_str();

(if the string is actually what's needed, I mean)...

:)

V
 
A

Alf P. Steinbach

* Victor Bazarov:
Alf said:
[...]
But note that

int main()
{
std::string const& str = std::string( "Hello, world!" );
const char* s = std.c_str();

... str.c_str();
std::cout << s << std::endl;
}

is not UB, because that reference to const keeps the temporary, so to speak.

Yes, but why would anybody do that, when it's SO much easier to do

std::string const str("whatever");
const char* s = str.c_str();

(if the string is actually what's needed, I mean)...

I just thought I should mention it, in case the OPs example code was more
like an impression of the code in question.
 
A

Adrian

What I meant is that by declaring
std::string const& str = std::string( "Hello, world!" );
you just define an alias for the object, the object itself is still allowed
to go out of scope. I don't have the standard handy but I don't think the
compiler is required to keep the object around for the lifetime of the
reference. I think you are confusing the reference concept with the one from
grabage collected languages where a reference will indeed prevent the object
from being destroyed.

If what you're saying was true life would be sweet because we could do
things like this:

const std::string& foo()
{
return std::string("foo");
}

This looks like an efficient way to return a std::string, unfortunately it
doesn't work.

Adrian
 
A

Alf P. Steinbach

* Adrian:
[top-posting]

Please don't top-post in this group -- read the FAQ.


* Adrian:
What I meant is that by declaring
std::string const& str = std::string( "Hello, world!" );
you just define an alias for the object, the object itself is still allowed
to go out of scope. I don't have the standard handy but I don't think the
compiler is required to keep the object around for the lifetime of the
reference.

It is; and do get yourself a copy of the standard.

If what you're saying was true life would be sweet because we could do
things like this:

const std::string& foo()
{
return std::string("foo");
}

Sorry, that's incorrect.
 
A

Adrian

Please don't top-post in this group -- read the FAQ. Sorry.



* Adrian:

It is; and do get yourself a copy of the standard.

Would you mind pointing me to the actual wording that mandates this? Thanks.
 
A

Alf P. Steinbach

* Adrian:
Would you mind pointing me to the actual wording that mandates this? Thanks.

Not at all, it's my pleasure. Navigating the standard is an art, not a
science, but an example such as this may help. To follow this example
you'll need to get hold of the standard (if you don't have it) or
alternatively the CD2, the last committee draft before the 98 standard.

The natural first place to look is in section 7, "Declarations".

However, there's seemingly nothing there, so the second natural choice is
section 8, "Declarators". And indeed there's some hinting about this in
§8.5.3 "References". But that's not the full story, and not definitive.

One might then be tempted to look in section 3 "Basic Concepts", subsection
3.7 "Storage duration", but alas, there's nothing relevant there.

And in fact, it's necessary to either be very patient and peruse long lists
of hits from the search function, or already know where what one is looking
for is (I chose the latter since it's way easier!), namely section 12
"Special member functions" -- and now I can almost hear some readers
screaming "What the heck has references to temporaries to do with special
member functions?", to which the answer is copy constructors -- subsection
12.2 "Temporary objects", and there (I won't lead you to the actual
paragraph) it is.
 
G

Gabor Drasny

Thank you guys for all the responses. I was secretly hoping that someone
would disprove my suspicion, but confirming it is useful, too.
Yes, but why would anybody do that, when it's SO much easier to do

std::string const str("whatever");
const char* s = str.c_str();

(if the string is actually what's needed, I mean)...

:)

V

The example I sent was admittedly a little stupid for the sake of
brevity, the situation that occurs frequently in my project is more like

std::string foo(<args>);
....
const char* s = foo(<args>).c_str();

or even

const char* s = (foo(<args1>) + foo(<args2>)).c_str();


One more followup question:

I am right to assume that the following is not UB:

int bar(const char* s) { ... }
std::string foo(int k) { ... }
....
int n = bar(foo(k).c_str());


Thanks,
Gabor Drasny
 
M

msalters

Gabor Drasny schreef:
I am right to assume that the following is not UB:

int bar(const char* s) { ... }
std::string foo(int k) { ... }
...
int n = bar(foo(k).c_str());

Yes. The temporary returned from foo(k) is destroyed
after n is assigned to. That means the const char* is
also valid until that time. bar() obviously was called
and has returned before the assignment to n

HTH,
Michiel Salters.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top