2

I am a C# developer and I find strange that when I run the following code in C++:

std::string original = "Hello";

std::string st = original + "World";
const char *c = st.c_str();

const char *c2 = (original + "World").c_str();

std::cout << "c  = '" << c << "'" << std::endl;
std::cout << "c2 = '" << c2 << "'" << std::endl;

I get the following output:

c  = 'HelloWorld'
c2 = ''

In C# a similar construct will result in c and c2 having the same value ("Hello World"). My guess would be that the scope of the result of (original + "World") ends on the right ), so c_str() is called on an invalid input. Is that correct? Is there a better way of achieving this other than creating variables to hold temporary results?

Thanks!

  • 2
    The problem is that you have a pointer to a buffer that is invalidated after the object is destroyed. Try this instead `std::cout << "c2 = '" << (original + "World").c_str() << "'" << std::endl;` – imreal Aug 04 '15 at 14:43
  • @imreal http://ideone.com/ovt8Ls it works (both). – VP. Aug 04 '15 at 14:44
  • 1
    @VictorPolevoy: Such is the nature of undefined behavior. – Fred Larson Aug 04 '15 at 14:47
  • @FredLarson yes, seems so. – VP. Aug 04 '15 at 14:47
  • 1
    @VictorPolevoy even if you see desired output that does not mean it works – Slava Aug 04 '15 at 14:47
  • You can use the `std::string`s directly in `cout`. You do not have to use `c_str()`. – mch Aug 04 '15 at 14:48
  • I'm using Visual Studio 2013 (v120) on Windows 7 Enterprise – PadawanLondon Aug 04 '15 at 14:50
  • And I don't need to use the code above as is. I just posted a simplified version to highlight my issue. I need to use a `char*` because I'm marshalling between C++ and C#. – PadawanLondon Aug 04 '15 at 14:55
  • 1
    I don't see the purpose in drawing conclusions on what C++ should do based on what C# does. You know they're _different languages_, right? – Lightness Races in Orbit Aug 04 '15 at 14:56
  • @LightnessRacesinOrbit -- I certainly know that they are different! But I'm much less experienced in C++ than in C#, so the purpose of this question was exactly to understand those differences – PadawanLondon Aug 04 '15 at 14:59
  • 1
    It would be more constructive to learn how C++ works in isolation than to learn it as a function of differences from some other language. – Lightness Races in Orbit Aug 04 '15 at 15:02
  • If you're going to write C++, get a good C++ book ( [look for one here](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list?lq=1) )and learn it properly. C++ doesn't work like C#. C++ strings are NOT immutable. `string s = "Hello"; s += " World"; cout << s;" will print "Hello World". – Rob K Aug 04 '15 at 15:18

2 Answers2

4

My guess would be that the scope of the result of (original + "World") ends on the right ), so c_str() is called on an invalid input. Is that correct?

Not quite, but close. c_str() itself is fine, but that pointer become invalid after the end of the statement, so using c2 afterwards leads to UB.

Is there a better way of achieving this other than creating variables to hold temporary results?

You can assign it to const reference:

const std::string &ref = original + "World";
const char *c2 = ref.c_str();

But I don't think that any better than creating variable.

Slava
  • 43,454
  • 1
  • 47
  • 90
2

'c2' here is initialized with a pointer into a temporary object that ceases to exist at the semicolon. Therefore this is undefined behavior. You'll need to use an intermediate variable:

const auto temp(original + "World");
const char* c2 = temp.c_str();
Fred Larson
  • 60,987
  • 18
  • 112
  • 174
  • 1
    Additional comment: Coming from the C# world you are used to having your memory managed for you with garbage collection etc. There you would end up with a reference to the temporary object so it would stick around. In C++ you have to be much more aware of the lifetime of objects. – Dale Wilson Aug 04 '15 at 14:48