2

I have a function that reads a file and returns a string.

string get_file_contents(const char *filename)
{
    ifstream in(filename);
    if (in)
    {
        ostringstream contents;
        contents << in.rdbuf();
        in.close();
        return(contents.str());
    }
    throw(errno);
}

I read a file containing only success and convert the return value it into a c style string in two different ways with different results.

string str = get_file_contents("test.txt");
const char* str1 = str.c_str();
cout << "printing str1: ";
cout << str1 << endl;
const char* str2 = get_file_contents("test.txt").c_str();
cout << "printing str2: ";
cout << str2 << endl;

output:

printing str1: success
printing str2:

I don't understand why str2 is empty. Any insight is appreciated.

slmyers
  • 697
  • 1
  • 6
  • 19

3 Answers3

3

With str1 you are setting it to the internals of a local variable str which remains valid until it goes out of scope at the end of the function (as long as you don't modify str).

With str2 you point it at the internals of a temporary string that is never assigned to a local variable and so it gets destroyed immediately after you assigned it.

Galik
  • 42,526
  • 3
  • 76
  • 100
3

Your function call returns a string which is temporary in both cases. Calling c_str() on that temporary returns a pointer that may be dangling after the statement completes. Using the string to store the result is correct, which is why the first call works. The second call may have undesirable effects due to the dangling pointer.

Since str2 is a pointer, it's not simply empty, it's pointing to a non-existent string. This could be a danger.

Storing the result into another string, as in the first call, might be optimized well by the compiler.

You may be able to shorten that file read as well:

...
ifstream in(filename);
if (in)
{
    return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>());
}

// throw exception
...
Dave May
  • 46
  • 2
  • 2
    Faster implementations are discussed in http://stackoverflow.com/questions/2912520/read-file-contents-into-a-string-in-c also. – Dave May Nov 26 '15 at 04:35
2

The problem is that the pointer returned by c_str() remains valid only for as long as the string from which it is obtained is not modified or disposed.

When you do this

const char* str2 = get_file_contents("test.txt").c_str();

the string returned by get_file_contents("test.txt") is temporary. The call to c_str() returns a pointer to its internal content, but then the string gets destroyed, making the return invalid.

Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399