why is std::cout convertible to void* if using g++?
Asked Answered
G

3

13

Why can one cast a std::ostream to a void pointer? I am not aware of any such conversion operator in std::ostream. Code below

#include <iostream>

int main()
{
    void *p = std::cout; // why does this work? 
}

I'm asking this question since I've seen a placement operator new invoked as

Foo* pFoo = new (std::cerr) Foo;

and have absolutely no idea why would one write such a thing.

PS: I am compiling with g++ 4.9.2 with or without -std=c++11. clang++ does not accept the code.

PSS: Found out that due to the so called "safe bool problem" (see @nicebyte's answer), in pre C++11 a void* conversion operator was defined for std::ostream, which was then removed in C++11. However, my code compiles fine in C++11 using g++. More than that, clang++ rejects it no matter what version of the standard I use, even with -std=c++98, although my understanding is that it should accept if compiled as pre-C++11.

Gisellegish answered 21/1, 2015 at 5:31 Comment(5)
new (std::cerr) Foo ? What. The. Hell.Burcham
@Burcham :) that's what I told myself when I saw that.Gisellegish
I would love it if you could provide the source. I can only think of horrible things this could lead to.Burcham
It's in Scott Meyers' book "Effective C++", item 52, page 291 (3rd edition)Gisellegish
Well I learnt something today, thanks ! That's a strange critter for sure...Burcham
P
11

Read this (your question is answered in the very last section, "The safe bool problem").

To elaborate a bit, the implementation defines an implicit conversion to void* defined for things like std::cin and std::cout, just so that code like while(std::cin>>x){...} compiles, while code like int x = std::cin; doesn't. It's still problematic because you can write stuff like in your example.

C++11 solves this problem by introducing explicit conversions.

An explicit conversion operator looks like this:

struct A {
 explicit operator B() { ... } // explicit conversion to B
};

When A has an explicit conversion to B, code like this becomes legal:

A a;
B b(a);

However, code like this is not:

A a;
B b = a;

A construct like if(std::cin) requires cin to be converted to bool, the standard states that in order for the conversion to be valid in that particular case, code like bool x(std::cin); should be "legal". Which can be achieved by adding an explicit conversion to bool. It allows cin/cout to be used in the above context, while avoiding things like int x = std::cout;.

For more information, refer to Bjarne's page as well as this question.

Prowess answered 21/1, 2015 at 5:37 Comment(4)
I have edited my answer to provide more detail (and included information on C++11 as well).Prowess
@nicebyte, thanks, was aware of explicit operators, but didn't know that there is a void* conversion operator for std::ostream. However, in C++11 it seems that this void* conversion was eliminated, due to the introduction of explicit conversion to bool. However my code still works even with -std=c++11 in g++, so I guess it's a flaw in the libstdc++ implementation. In clang++, even if I use -std=c++98, the code still does not compile.Gisellegish
I don't think the standard explicitly states that cin/cout MUST be implemented to use explicit conversion to bool. It might also be that g++ has left in the implicit void* conversion because of some weird backwards compatibility considerations.Prowess
@nicebyte: excellent answer. Thanks for giving cppreference link in ur answer.Dumfries
N
4

Answering only the follow-up, since nicebyte's answer is perfect for the original question.

Chances are, your gcc is set up to use libstdc++ (which hasn't changed the operator yet due it being an ABI-breaking change), and your clang is set up to use libc++ (which was from the beginning intended as a C++11 standard library and isn't quite conformant in C++98 mode - it provides a bool conversion operator that is explicit in C++11).

Nosography answered 21/1, 2015 at 15:38 Comment(0)
J
2

I think it's to allow for if (std::cout) ... without allowing for implicit conversion to bool, or something like that.

Jordaens answered 21/1, 2015 at 5:32 Comment(1)
IIRC, this answer appeared in the low quality post review queue. I categorised it as not an answer because of the use of I think and something like that, for me it looked like a comment, not an answer. But I don't know C++, I'm sorry if this is a valid answer and if it was a mistake to flag it.Feign

© 2022 - 2024 — McMap. All rights reserved.