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

Strange behavior with Standard C++ 'string' objects

P: n/a
Hello,

I'm new to the boards, and I've been struggling with a problem porting my
company's code from Visual C++ 6.0 to Visual C++ 2005.

We've found some crashes that I've traced to the 'c_str()' member of the
standard string class. I've debugged into the deepest layers of the system
code and cannot explain this.

What we have is a class with a private 'string' member:

string _linkType;

And public function that returns it:

class Link
....
string getLinkType() const {return _linkType; }

When attempting to access the string as a char * later in the code, the
resulting string "1M" does not get extracted properly:

Link *ilink;
const char *pLinkType;
pLinkType = ilink->getLinkType().c_str();

The result of this is that pLinkType is "".

Now - here's the weird part.

const char *blah;
string strvalue;
strvalue = ilink->getLinkType();
blah = strvalue.c_str();

If I do this, 'blah' contains the proper string '1M'.

How can this be? If I break apart the operation into two lines, it works.
Keep it as one line and it fails!?

I've tried defining the member as std::string and return value from the get
function as std::string as well, with no change in behavior. I'd really
like a good solution to this, as this example literally shows up hundreds of
times in our code. It would be a lot of work to make the massive changes to
ensure the proper value is getting returned.

This works just fine in Visual C++ 6.0. I've even installed VC++2005 SP1 to
see if it was fixed there, with no change.

Thanks so much in advance for your help!
Mar 8 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Brian Kunz wrote:
Hello,

I'm new to the boards, and I've been struggling with a problem
porting my company's code from Visual C++ 6.0 to Visual C++ 2005.

We've found some crashes that I've traced to the 'c_str()' member of
the standard string class. I've debugged into the deepest layers of
the system code and cannot explain this.

What we have is a class with a private 'string' member:

string _linkType;

And public function that returns it:

class Link
....
string getLinkType() const {return _linkType; }

When attempting to access the string as a char * later in the code,
the resulting string "1M" does not get extracted properly:

Link *ilink;
const char *pLinkType;
pLinkType = ilink->getLinkType().c_str();

The result of this is that pLinkType is "".
This produces a pointer into a temporary return value, which disappears at
the semi-colon.
>
Now - here's the weird part.

const char *blah;
string strvalue;
strvalue = ilink->getLinkType();
blah = strvalue.c_str();

If I do this, 'blah' contains the proper string '1M'.
Because "1M" is saved inside strvalue, and blah points to that value. blah
is valid as long at strvalue doesn't change.
>
This works just fine in Visual C++ 6.0.
No it didn't. It just seemed to work. :-)
I've even installed VC++2005
SP1 to see if it was fixed there, with no change.
That's a good idea anyway.

Bo Persson
Mar 8 '07 #2

P: n/a
Brian Kunz wrote:
Link *ilink;
const char *pLinkType;
pLinkType = ilink->getLinkType().c_str();

The result of this is that pLinkType is "".
What happens here is that getLinkType() returns a temporary object.
You're not storing it anywhere, so it gets destructed as soon as the
assignment is executed. c_str() is getting a pointer to a member of this
temporary string. When the string returned by getLinkType() goes out of
scope, the const char* returned by c_str() gets invalidated too.
const char *blah;
string strvalue;
strvalue = ilink->getLinkType();
blah = strvalue.c_str();

If I do this, 'blah' contains the proper string '1M'.
That works as expected, since the string returned by getLinkType is no
longer a temporary. You have a local copy of it, so blah will be valid
as long as strvalue is alive. However, as soon as strvalue goes out of
scope, the value of blah will become undefined.
How can this be? If I break apart the operation into two lines, it works.
Keep it as one line and it fails!?
It's not a matter of having 1 line or 2 lines, it has to do with the
temporary. You have to remember that unless you declare a variable and
give a name to it, it's nothing more than a temporary that dies at the
end of the instruction (when the semicolon is closed). Getting a pointer
to a temporary, or one of its members, is pretty dagerous an unpredictable.

In VC6 the compiler didn't immediately destroy your temporary, so your
pointer was still alive. However, there's no such guarantee. You were
exploiting undefined behavior, and with VC++ 2005 your luck has turned
around. In fact, you should be happy that you caught a bug, because it
was always hanging in the air, waiting for an accident to happen.

Tom
Mar 8 '07 #3

P: n/a
Thank you both so much for your help. What you're saying makes complete
sense. I guess that fact that it worked in 6.0 led me to believe a change in
behavior. Bottom line is, we got lucky and our luck ran out.

Thanks again!

"Tamas Demjen" wrote:
Brian Kunz wrote:
Link *ilink;
const char *pLinkType;
pLinkType = ilink->getLinkType().c_str();

The result of this is that pLinkType is "".

What happens here is that getLinkType() returns a temporary object.
You're not storing it anywhere, so it gets destructed as soon as the
assignment is executed. c_str() is getting a pointer to a member of this
temporary string. When the string returned by getLinkType() goes out of
scope, the const char* returned by c_str() gets invalidated too.
const char *blah;
string strvalue;
strvalue = ilink->getLinkType();
blah = strvalue.c_str();

If I do this, 'blah' contains the proper string '1M'.

That works as expected, since the string returned by getLinkType is no
longer a temporary. You have a local copy of it, so blah will be valid
as long as strvalue is alive. However, as soon as strvalue goes out of
scope, the value of blah will become undefined.
How can this be? If I break apart the operation into two lines, it works.
Keep it as one line and it fails!?

It's not a matter of having 1 line or 2 lines, it has to do with the
temporary. You have to remember that unless you declare a variable and
give a name to it, it's nothing more than a temporary that dies at the
end of the instruction (when the semicolon is closed). Getting a pointer
to a temporary, or one of its members, is pretty dagerous an unpredictable.

In VC6 the compiler didn't immediately destroy your temporary, so your
pointer was still alive. However, there's no such guarantee. You were
exploiting undefined behavior, and with VC++ 2005 your luck has turned
around. In fact, you should be happy that you caught a bug, because it
was always hanging in the air, waiting for an accident to happen.

Tom
Mar 8 '07 #4

P: n/a
In article <F0**********************************@microsoft.co m>,
=?Utf-8?B?QnJpYW4gS3Vueg==?= <Br*******@discussions.microsoft.comwrote:
>Thank you both so much for your help. What you're saying makes
complete sense. I guess that fact that it worked in 6.0 led me to
believe a change in behavior. Bottom line is, we got lucky and our
luck ran out.
I think you're going to find that 2005 is a real nitpicker when it
comes to sketchy code. I much prefer things to fail instantly and
obviously, rather than being lucky.

Nathan Mates

--
<*Nathan Mates - personal webpage http://www.visi.com/~nathan/
# Programmer at Pandemic Studios -- http://www.pandemicstudios.com/
# NOT speaking for Pandemic Studios. "Care not what the neighbors
# think. What are the facts, and to how many decimal places?" -R.A. Heinlein
Mar 8 '07 #5

P: n/a

"Brian Kunz" <Br*******@discussions.microsoft.comwrote in message
news:F0**********************************@microsof t.com...
Thank you both so much for your help. What you're saying makes complete
sense. I guess that fact that it worked in 6.0 led me to believe a change
in
behavior. Bottom line is, we got lucky and our luck ran out.
This is the fix you are probably looking for, that won't require a million
changes to scattered code:

class Link
....
const std::string& getLinkType() const {return _linkType; }

pLinkType = ilink->getLinkType().c_str(); // now OK
Mar 8 '07 #6

P: n/a


"Ben Voigt" wrote:
This is the fix you are probably looking for, that won't require a million
changes to scattered code:

class Link
....
const std::string& getLinkType() const {return _linkType; }

pLinkType = ilink->getLinkType().c_str(); // now OK
YES YES! Perfect! That works wonderfully, thank you so much.
Mar 8 '07 #7

P: n/a

"Brian Kunz" <Br*******@discussions.microsoft.comwrote in message
news:06**********************************@microsof t.com...
>

"Ben Voigt" wrote:
>This is the fix you are probably looking for, that won't require a
million
changes to scattered code:

class Link
....
const std::string& getLinkType() const {return _linkType; }

pLinkType = ilink->getLinkType().c_str(); // now OK
YES YES! Perfect! That works wonderfully, thank you so much.
Note that the string object is now the actual member variable, so the
lifetime is now equal to the lifetime of the object ilink refers to. That's
probably long enough for all callers, but it might not always be.
Mar 9 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.