c++ w/vs2010 and temporaries

Started by
4 comments, last by Aardvajk 12 years, 2 months ago
[font=tahoma,geneva,sans-serif]Ok, here is a question I am absolutely clueless on. Hopefully someone here can help! At work we have a function like so:[/font]
[font=tahoma,geneva,sans-serif]bool GetFolder(String &folderpath, const String &caption = "", HWND hOwner = NULL) {
... bla bla bla ...
bi.lpszTitle = caption.IsEmpty() ? 0 : caption;
... bla bla bla ...
[/font]

[font=tahoma,geneva,sans-serif]Now, String has the following members (this is of course not an exhaustive listing)[/font]
[font=tahoma,geneva,sans-serif]INLINE String(const String &Text) : InternalString_(Text.InternalString_) { }
INLINE operator const wchar_t*() const { return InternalString_.c_str(); }
INLINE const wchar_t *GetPtrW() const { return InternalString_.c_str(); }
[/font]

[font=tahoma,geneva,sans-serif]And in the above, InternalString_ is just a std::wstring.[/font]

[font=tahoma,geneva,sans-serif]Now, here's my question, if anyone has any wonderful insight! In vs2008, the above line of code in GetFolder does as I expected, and we get a pointer to the string stored inside the object actually referenced by the caption variable. [/font][font=tahoma, geneva, sans-serif]However, in vs2010, a temporary String object is created, which we get the pointer to the string inside it, which of course vanishes into oblivion immediately following that line of code, giving us crazy nonsensical strings and other wonderful unsafe behavior.[/font]

[font=tahoma, geneva, sans-serif]Can anyone tell me why it is creating a temporary? If I use "GetPtrW" or an explicit cast it works fine... but there are a lot of places in code that use the implicit cast.[/font]
Advertisement
On the chance that anyone was interested in the problem above

And the answer is: There wasn't enough information in my original post! (of course I didn't realize this at the time)

Missing information: The String class here also has implicit conversion from many built in types (such as int) to String using other
constructors in String (which I didn't list above).

So then...

What is happening here is not exactly what I thought previously. That ternary operator can't change types, so it is returning a String (the choices being String, or integer). In order to do this, it is implicitly creating a temporary String, which gets assigned a copy of "caption", or a converted value 0. That temporary string is where the cast to LPCTSTR happens, and of course disappears after the statement has executed.

By changing the "0" to "(LPCTSTR)0" or some such thing (better yet, "(LPCTSTR)nullptr"), we end up with the ternary operator outputting a temporary LPCTSTR, which instead of implicitly converting the 0 or the nullptr, it implicitly converts the "caption" variable to const wchar_t * type, which is what we originally wanted.

Phew.
Thanks for posting the follow up. I was curious, and thought an additional constructor might be involved, but wasn't aware of how the ternary operator might be affecting this.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Thanks for posting the follow up. I was curious, and thought an additional constructor might be involved, but wasn't aware of how the ternary operator might be affecting this.

The ironic things is that if the "convenient" constructors of String for converting integers and floats and such to String weren't there, the compiler would have complained that it can't convert the integer 0 to a String, and we would have been good to go.

[quote name='Cornstalks' timestamp='1328653232' post='4910657']
Thanks for posting the follow up. I was curious, and thought an additional constructor might be involved, but wasn't aware of how the ternary operator might be affecting this.

The ironic things is that if the "convenient" constructors of String for converting integers and floats and such to String weren't there, the compiler would have complained that it can't convert the integer 0 to a String, and we would have been good to go.
[/quote]

More accurately they should have been written to have explicit constructors, which segways into the C++ standard should have had explicit be the default behavior.
http://www.gearboxsoftware.com/

More accurately they should have been written to have explicit constructors, which segways into the C++ standard should have had explicit be the default behavior.


This is more a good example of why a string class should not have an operator const char*. There are good reasons that std::string lacks this.

blah = (test ? 0 : str.c_str());

would not have exhibited these problems. Plus the whole plethora of other gotchas that arise from implicitly converting what is essentially a very temporary buffer into a normal pointer to char.

This topic is closed to new replies.

Advertisement