Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / Managed C++ / March 2007

Tip: Looking for answers? Try searching our database.

Strange behavior with Standard C++ 'string' objects

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Brian Kunz - 08 Mar 2007 19:01 GMT
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!
Bo Persson - 08 Mar 2007 19:15 GMT
> Hello,
>
[quoted text clipped - 23 lines]
>
> 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.
>
[quoted text clipped - 4 lines]
>
> 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
Tamas Demjen - 08 Mar 2007 19:20 GMT
> 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
Brian Kunz - 08 Mar 2007 19:36 GMT
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!

> > Link *ilink;
> > const char *pLinkType;
[quoted text clipped - 36 lines]
>
> Tom
Nathan Mates - 08 Mar 2007 19:46 GMT
>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
Ben Voigt - 08 Mar 2007 22:46 GMT
> 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
Brian Kunz - 08 Mar 2007 23:28 GMT
> This is the fix you are probably looking for, that won't require a million
> changes to scattered code:
[quoted text clipped - 4 lines]
>
> pLinkType = ilink->getLinkType().c_str(); // now OK

YES YES!  Perfect!  That works wonderfully, thank you so much.
Ben Voigt - 09 Mar 2007 16:41 GMT
>> This is the fix you are probably looking for, that won't require a
>> million
[quoted text clipped - 7 lines]
>>
> 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.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.