Rodrigo Queiro
Rodrigo Queiro

Reputation: 1336

Anonymous std::ofstream handles character array wrongly

The following code outputs a string literal to a file with both anonymous and named streams:

#include <fstream>

using namespace std;

int main()
{
    ofstream("testfile") << "test" << endl;

    ofstream ofs ("testfile2");
    ofs << "test2" << endl;

    return 0;
}

As you can see from strace's output, only the named stream works:

open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(3, "0x400a91\n", 9)               = 9
close(3)                                = 0
open("testfile2", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(3, "test2\n", 6)                  = 6
close(3)                                = 0

Also, if you use std::string instead of a literal, it fails to compile.

Why is this?

Upvotes: 6

Views: 252

Answers (2)

ecatmur
ecatmur

Reputation: 157364

In C++03, the non-member operators that output character pointers and strings cannot be called with an rvalue, as they require an lvalue reference, so the member operator<<(const void *) is called. In C++11 this is solved by writing overloads that take an rvalue reference, but in C++03 you can work around it by calling a member function or member operator that returns an lvalue reference (note that non-const member functions can be called on rvalues):

ofstream("testfile").write("", 0) << "test" << endl;

You can easily write a manipulator to do this:

std::ios_base& (*do_nothing)(std::ios_base&) ) {}

ofstream("testfile") << do_nothing << "test" << endl;

Upvotes: 4

Bo Persson
Bo Persson

Reputation: 92271

You have a problem that the "anonymous stream" is an rvalue, and with C++98 you can only call member functions on it. The stream << "test" will bind to a member taking a void* that outputs the pointer's address.

C++11 has added an operator<< that takes an rvalue stream, and that will make the code work.

Upvotes: 9

Related Questions