 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Enrico Righes Guest
|
Posted: Sat Jan 17, 2004 3:11 am Post subject: strange string-behaviour |
|
|
hi there
given following simple code:
#include <string>
#include <iostream>
using namespace std;
string foo(string s)
{
return s + " z";
}
int main()
{
const char *s1 = foo("a").c_str();
string s2 = foo("b"); (1)
cout << s1 << endl;
cout << s2.c_str() << endl; (2)
}
The output rather than
a z
b z
it is (Linux g++ 3.3.1 & VC++ 6.0)
b z
b z
In VC++ Debug modus without lines (1) & (2) the output is only junk
(seems that the string-data is deallocated).
Can anybody explain this? Thx in advance!
Enrico
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jack Klein Guest
|
Posted: Sat Jan 17, 2004 11:05 am Post subject: Re: strange string-behaviour |
|
|
On 16 Jan 2004 22:11:33 -0500, [email]righes (AT) freenet (DOT) de[/email] (Enrico Righes) wrote
in comp.lang.c++.moderated:
| Quote: | hi there
given following simple code:
#include
#include
using namespace std;
string foo(string s)
{
return s + " z";
}
int main()
{
const char *s1 = foo("a").c_str();
|
Here you have created a temporary string object and used the c_str()
member function to have it generate a C style string, an array of two
characters 'a' and ' '. But this is a temporary string object. Its
lifetime ends, and its destructor is called, at the end of the
statement. Your pointer s1 is now invalid, pointing to an object
whose lifetime has ended. Any use of this pointer after the temporary
string has been destroyed, which is at the semicolon ending the
assignment statement, produces undefined behavior.
| Quote: | string s2 = foo("b"); (1)
cout << s1 << endl;
cout << s2.c_str() << endl; (2)
}
The output rather than
a z
b z
it is (Linux g++ 3.3.1 & VC++ 6.0)
b z
b z
|
It just so happens that the new string s2 happens to reuse the memory
just used to hold the temporary string created in the line above it.
There is no requirement in the C++ standard that says this must
happen, but given the way many compilers manage memory it is not
surprising.
| Quote: | In VC++ Debug modus without lines (1) & (2) the output is only junk
(seems that the string-data is deallocated).
|
Yes the string data is deallocated at the ; ending the statement
assigning to the pointer s1. So it becomes a dangling pointer. That
is the way temporary object work, unless they are bound to a constant
reference. They disappear at the end of the statement.
| Quote: | Can anybody explain this? Thx in advance!
Enrico
|
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ivan Vecerina Guest
|
Posted: Sat Jan 17, 2004 11:07 am Post subject: Re: strange string-behaviour |
|
|
"Enrico Righes" <righes (AT) freenet (DOT) de> wrote
Hi Enrico,
| Quote: | const char *s1 = foo("a").c_str();
This line of code is the source of the bug: |
The pointer returned by c_str() can only be used as long
as the std::string object isn't modified or destroyed.
foo("a") returns a temporary string object that will
be destroyed at the end of the statement (at the .
From then on, accessing data pointed to by s1 leads
to undefined behavior.
| Quote: | cout << s1 << endl;
|
Whenever c_str() is called, one has to make sure that
the returned pointer isn't used beyound the lifetime
of the string object (or after the string is modified).
Storing the result of c_str() in a pointer variable
is almost always a bad idea.
[ This is the reason why std::string does not provide
an *implicit* conversion to "const char*", as other
popular string classes do: it is too dangerous. ]
| Quote: | The output rather than
a z
b z
it is (Linux g++ 3.3.1 & VC++ 6.0)
b z
b z
....
Can anybody explain this? Thx in advance!
|
It seems that the second string defined in your program
just happened to be allocated at the same address as s1.
hth,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Sat Jan 17, 2004 11:29 pm Post subject: Re: strange string-behaviour |
|
|
[email]righes (AT) freenet (DOT) de[/email] (Enrico Righes) writes:
| Quote: | #include <string
#include
|
[Unrelated to your problem:]
#include
is missing here, or the overload of operator<< for char const * may not
be available below, which would mean that the overload for void const *
would be used.
| Quote: | using namespace std;
string foo(string s)
{
return s + " z";
}
int main()
{
const char *s1 = foo("a").c_str();
[snip]
cout << s1 << endl;
|
You are calling c_str() on a string object; this string object is then
immediately destructed.
According to the Standard (21.3.6), using the return value of c_str() after
"any subsequent call to a non-const member function" of the string object
has undefined behavior. The destructor is such a non-const member function.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Peter Kragh Guest
|
Posted: Sat Jan 17, 2004 11:32 pm Post subject: Re: strange string-behaviour |
|
|
Enrico Righes wrote:
| Quote: | int main()
{
const char *s1 = foo("a").c_str();
string s2 = foo("b"); (1)
cout << s1 << endl;
cout << s2.c_str() << endl; (2)
}
The output rather than
a z
b z
it is (Linux g++ 3.3.1 & VC++ 6.0)
b z
b z
In VC++ Debug modus without lines (1) & (2) the output is only junk
(seems that the string-data is deallocated).
Can anybody explain this? Thx in advance!
|
I'll try.
The problem is this line of code:
const char *s1 = foo("a").c_str();
Two things to notice: 1) The foo function creates a *temporary* instance of
a string class (i.e. at the end of the expression, the strings destructor is
called). 2) c_str() *doesn't copy* the contents of the string.
The result: s1 points to some garbage.
HTH
- Peter
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Sat Jan 17, 2004 11:32 pm Post subject: Re: strange string-behaviour |
|
|
In message <19687458.0401160654.26295813 (AT) posting (DOT) google.com>, Enrico
Righes <righes (AT) freenet (DOT) de> writes
| Quote: | hi there
given following simple code:
#include
#include
using namespace std;
string foo(string s)
{
return s + " z";
}
int main()
{
const char *s1 = foo("a").c_str();
|
c_str() provides a char[] based on the value of the string object which
is only valid until something changes the string. Unfortunately the
string returned by foo() is a temporary and disappears at the end of the
above statement. The result is that s1 becomes a hanging pointer and
dereferencing it will have undefined behaviour.
| Quote: | string s2 = foo("b"); (1)
|
This one, in itself is fine, but as you have already exercised undefined
behaviour the result will also be undefined (UB permeates through code
from the point where it happens)
| Quote: |
cout << s1 << endl;
cout << s2.c_str() << endl; (2)
|
BTW, unless you have a real reason to force flushing of a stream, use
'n' instead of endl.
| Quote: | }
The output rather than
a z
b z
it is (Linux g++ 3.3.1 & VC++ 6.0)
b z
b z
Yes, clearly they are recycling the space for the temporary, as they |
are fully entitled to do.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Mang Guest
|
Posted: Sat Jan 17, 2004 11:40 pm Post subject: Re: strange string-behaviour |
|
|
Enrico Righes schrieb:
[snip]
| Quote: |
int main()
{
const char *s1 = foo("a").c_str();
|
Here, the function foo("a") returns a temporary string. c_str() extracts
the information of the string as C-style array and initializes s1 with
it, but then the string dies (and along with it the memory s1 points
to). s1 points to invalid memory after the expression.
| Quote: |
string s2 = foo("b"); (1)
|
Here you copy initialize a new string from the temporary created by
foo("b"). s2 will allocate its own memory to store the string
information.
| Quote: |
cout << s1 << endl;
|
KaBoom. s1 points to invalid memory - undefined behavior
| Quote: |
cout << s2.c_str() << endl; (2)
}
|
safe, s2 owns the memory.
BTW, you try to output char const*, so you have to #include
additionally.
regards,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
DarkSpy Guest
|
Posted: Sun Jan 18, 2004 11:21 am Post subject: Re: strange string-behaviour |
|
|
at 16 Jan 2004 22:11:33 -0500 , [email]righes (AT) freenet (DOT) de[/email] (Enrico Righes)
wrote:
| Quote: | {
const char *s1 = foo("a").c_str();
foo("a") using copy constructor to new a string. |
| Quote: | string s2 = foo("b"); (1)
and foo("b")'s copy constructor is new a string, but the "b" 's bytes |
is too small to new on old address of foo("a");
[comp.lang.c++]
[comp.lang.c++.moderated]
DarkSpy, A C++ MadDog. :-)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|