Page 1 of 1

String corrupts after function return

Posted: Fri Feb 08, 2008 2:34 pm
by MickeyKnox
I don't know if have a irrlicht problem, or a general C++ problem.
Returning a wchar_t* seems to be corrupt somehow. I made a minimal
example to reproduce the error:

Code: Select all

#include <irrlicht.h>
#include <iostream>

using namespace irr;

const wchar_t* func()
{
  core::stringw Text(L"First line\nSecond line\nThird line");
  //core::stringw Text(L"text");

  core::stringc text(Text.c_str());
  std::cout << text.c_str() << std::endl;

  return Text.c_str();
}

int main()
{
  core::stringc text(func());
  std::cout << text.c_str() << std::endl;
}
The output of this is:

Code: Select all

First line
Second line
Third line
pprst line
Second line
Third line
For Text being just "text" the output is:

Code: Select all

text

I have absolutely no idea, what is going on here.

Re: String corrupts after function return

Posted: Fri Feb 08, 2008 3:04 pm
by randomMesh
MickeyKnox wrote:

Code: Select all

const wchar_t* func() 
{
   ...
}

int main()
{
  core::stringc text(func());
  std::cout << text.c_str() << std::endl;
}
What happens if you change core::stringc text(func()); to core::stringw text(func()); ?

Posted: Fri Feb 08, 2008 3:08 pm
by rogerborg
core::stringw Text is created on the stack. The memory that it allocates internally is on the heap, but when func() returns, Text is destroyed, its destructor is called, and its memory freed. You are returning a pointer to freed memory, which is being crapped over before you get a chance to copy the contents.

Code: Select all

const wchar_t* func()
{
  core::stringw Text(L"First line\nSecond line\nThird line");
  // Text now contains that string in memory allocated on the heap.
 
  return Text.c_str();
  // The function will now return a pointer to that heap memory

} // UH OH - Text is destroyed, and its destructor deletes the heap memory.  That makes it fair game to be re-used.
// The pointer to the destroyed memory is returned...

int main()
{
  // ...and here's func(), returning that pointer to the destroyed memory.
  // The contents of that memory could be anything.  You're seeing a couple of characters being crapped over
  // but the entire memory could be gibberish by the time it gets passed into the constructor of text()
  core::stringc text(func());

  std::cout << text.c_str() << std::endl;
} 

I'm not sure what your requirements are, but I'd recommend returning a stringw, either by value or reference.

E.g.

Code: Select all

core::stringw func()
{
  core::stringw Text(L"First line\nSecond line\nThird line");

  core::stringc text(Text.c_str());
  std::cout << text.c_str() << std::endl;

  return Text;
}

int main()
{
  core::stringc text(func().c_str());
  std::cout << text.c_str() << std::endl;
} // Note that the stringw returned from func() will be implicitly destroyed here
or

Code: Select all

void func(core::stringw & outString)
{
  outString = L"First line\nSecond line\nThird line";
 
  core::stringc text(outString.c_str());
  std::cout << text.c_str() << std::endl;
}

int main()
{
  core::stringw wideString;
  func(wideString);
  core::stringc text(wideString.c_str());
  std::cout << text.c_str() << std::endl;
} // Note that wideSrting will be implicitly destroyed here

Posted: Fri Feb 08, 2008 3:17 pm
by MickeyKnox
Thanks rogerborg. I just need to make my variable a class variable.
In my minimal example, making Text a global variable would work.

Posted: Fri Feb 08, 2008 3:27 pm
by Acki
I'm not sure why you return a wchar_t*, but if you return a strinc it should work:

Code: Select all

const stringc func(){
  core::stringc Text(L"First line\nSecond line\nThird line");

  return Text;
}

int main(){
  core::stringc text = func();
  printf("%s\n", text.c_str());

  return 0;
}

Posted: Fri Feb 08, 2008 3:27 pm
by MickeyKnox
Yes, thanks again. I observed, that returning a stringw would work, but i didn't got why. Thanks for your explanations.

I guess i stick with my class variable solution, since i want my GUIElement act like the irrlicht GUIElements, returning const wchar_t*

@randomMesh: a stringw wouldn't work, because i can't pass a wchar_t* to std::cout

Posted: Fri Feb 08, 2008 3:53 pm
by randomMesh
MickeyKnox wrote:@randomMesh: a stringw wouldn't work, because i can't pass a wchar_t* to std::cout
Yeah. I totally overlooked the heap / stack thing. I really should test my suggestions before posting them. :roll:

Posted: Fri Feb 08, 2008 4:58 pm
by Acki
MickeyKnox wrote:I observed, that returning a stringw would work, but i didn't got why
It's because you don't return a pointer/reference but you then return a copy of the stringc/w... ;)

Posted: Sat Feb 09, 2008 12:48 am
by pippy
I thought that wide characters needed to be printed out using std::wcout

Posted: Sat Feb 09, 2008 1:51 am
by Acki
it's stringc printed, not stringw... ;)