Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do streams still convert to pointers in C++11?

The canonical way to read lines from a text file is:

std::fstream fs("/tmp/myfile.txt");
std::string line;
while (std::getline(line, fs)) {
   doThingsWith(line);
}

(no, it is not while (!fs.eof()) { getline(line, fs); doThingsWith(line); }!)

This works beacuse std::getline returns the stream argument by reference, and because:

  • in C++03, streams convert to void*, via an operator void*() const in std::basic_ios, evaluating to the null pointer value when the fail error flag is set;
    • see [C++03: 27.4.4] & [C++03: 27.4.4.3/1]
  • in C++11, streams convert to bool, via an explicit operator bool() const in std::basic_ios, evaluating to false when the fail error flag is set
    • see [C++11: 27.5.5.1] & [C++11: 27.5.5.4/1]

In C++03 this mechanism means the following is possible:

std::cout << std::cout;

It correctly results in some arbitrary pointer value being output to the standard out stream.

However, despite operator void*() const having been removed in C++11, this also compiles and runs for me in GCC 4.7.0 in C++11 mode.

How is this still possible in C++11? Is there some other mechanism at work that I'm unaware of? Or is it simply an implementation "oddity"?

like image 375
Lightness Races in Orbit Avatar asked Feb 02 '13 03:02

Lightness Races in Orbit


3 Answers

I'm reasonably certain this is not allowed/can't happen in a conforming implementation of C++11.

The problem, of course, is that right now, most implementations are working on conforming, but aren't there completely yet. At a guess, for many vendors, this particular update is a fairly low priority. It improves error checking, but does little (or nothing) to enable new techniques, add new features, improve run-time efficiency, etc. This lets the compiler catch the error you've cited (some_stream << some_other_stream) but doesn't really make a whole lot of difference otherwise.

If I were in charge of updating a standard library for C++11, I think this would be a fairly low priority. There are other changes that are probably as easy (if not easier) to incorporate, and likely to make a much bigger difference to most programmers.

To use one of the examples you gave, if I were in charge of updating the VC++ standard library to take advantage of the compiler features added in the November CTP, my top priority would probably be to add constructors to the standard container types to accept initialization_lists. These are fairly easy to add (I'd guess one person could probably add and test them in under a week) and make quite an obvious, visible difference in what a programmer can do.

like image 200
Jerry Coffin Avatar answered Nov 07 '22 02:11

Jerry Coffin


As late as GCC 4.6.2, the libstdc++ code for basic_ios is evidently still C++03-like.

I'd simply put this down to "they haven't gotten around to it yet".

By contrast, the libc++ (LLVM's stdlib implementation) trunk already uses operator bool().

like image 30
Lightness Races in Orbit Avatar answered Nov 07 '22 00:11

Lightness Races in Orbit


This was a missed mini-feature buried in a pre-existing header. There are probably lots of missing error of omission and commission in pre-2011 components.

Really, if anyone comes up with things like this in gcc then it would do a world of good to go to Bugzilla and make a bug report. It may be a low priority bug but if you start a paper trail

I'll go out on a limb and extend this idea to all the other C++ compilers: clang, Visual Studio,etc.

This will make C++ a better place.

P.S. I entered a bug in Bugzilla.

like image 28
emsr Avatar answered Nov 07 '22 01:11

emsr