I am compiling an outdated project with my latest gcc g++ compilers, (version > 6)
There is a class CodeWriter with an ostream reference variable.
class CodeWriter
{
//private:
protected:
ostream &m_stream;
public:
CodeWriter(ostream &stream):m_stream(stream){}
~CodeWriter(){
if(m_stream != NULL){
m_stream.flush();
}
}
};
The class is quite large so I included only the relevant variables and functions.
As you can see the destructor seems to be comparing the reference to NULL.
This project compiled fine when I used it long back with old gnu toolchain.
But now it is throwing an error saying that there is no matching operator != to compare ostream and long int.
Can anyone explain the rationale behind the change, and how I can fix this?
I would be happy to provide additional information/ include the whole class if required.
The code is not comparing the reference itself with NULL, but comparing the referenced-object with NULL. References can't be NULL, and it's impossible to compare the reference itself with NULL.
And
This project compiled i when i used it long back with old gnu toolchain.
Because the behavior changed since C++11.
Before C++11, std::ostream could be implicitly converted to void* via operator void*(), which returns a null pointer if error has occurred on the stream. So the original intent of the code is to check whether the stream has no errors.
Since C++11 the conversion function was changed to explicit operator bool(), which returns false if error has occured. Note the function is declared as explicit, which means implicit conversion to bool is not allowed, so the code won't compile with C++11 again because std::ostream can't be converted to bool implicitly (and then to be compared with NULL (an integer literal)).
With a C++11-compatible compiler you can just change the code to
if (m_stream) {
m_stream.flush();
}
Note that for contextual conversions even explicit conversion functions are considered. For the above code, m_stream will be converted to bool via explicit operator bool(), then the value would be used for the condition of if.
Streams can always be evaluated in a boolean context, so just change it to:
if (m_stream) {
m_stream.flush();
}
C++11 made the conversion to bool explicit. This is equivalent to if (!m_stream.fail()). Prior to C++11, this short-hand checkability was achieved by providing an (implicit!) conversion to void*, which is why your old code used to work.
The reason the code is checking for this, rather than just calling m_stream.flush(); directly, is perhaps that the stream may have exceptions enabled for failure and that might throw, [update:] but, as #Arne pointed out, flush itself may fail and throw, too. If there are no exceptions, you can just skip the boolean check entirely.[/update]
The stream classes had an operator void*() in one of the base classes in pre-C++11. Of course the void* value could be compared to NULL.
In current C++ this is instead an explicit operator bool() which works in the context of the if statement, but not in a general expression.
The use of a void* was to avoid some unwanted conversions from bool that happened when we didn't have explicit operators.
Related
I have unearthed an old C++ DLL, and I'd like to us it in one of my projects, in VS2015.
The problem is, it does not compile. I got in touch with a guy in the team that made the code in the first place, and he is positive that the exact same code compiled with VS2010.
I have an error in an otherwise very simple function:
Extract of header:
/*
Data input
*/
istream* input; //Source of data
long inputpos; // Current position in the data stream
And the code itself:
// Helper function to increment a counter while reading a character
void* Calculator::inputstream_get(char& ch)
{
++inputpos;
return input->get(ch);
}
In the end, I get an Error C2440:
'return': cannot convert from 'std::basic_istream<char,std::char_traits<char>>' to 'void *'
It is my understanding (I'm not a C++ expert I have to say...) that void pointers could represent any type of data, am I mistaken?
Is there any way to 'cast' my istream to an void pointer?
Thanks a lot for your help
The reason why this compiles in VS 2010 (C++03) and not in VS 2015 (C++11) is that in C++03, standard library streams defined an implicit conversion to void*; the purpose of that conversion was to allow testing them for truthiness (such as while (cin >> x)) without allowing an implicit conversion to bool (which would allows such monstrosities as 1 + (cin >> x) to compile).
Note that the value of the returned void* was underspecified: it was either a null pointer when the stream is in a failed state, or an unspecified non-null pointer when the stram's in good state.
C++11 introduced the notion of explicit conversion operators and contextual conversion to bool, which means that these "hacky" conversions to void* were replaced in the standard by a safe explicit operator bool () const. Of course, this makes the code fail to compile as C++11.
How you can solve this is change Calculator::inputstream_get as follows:
void* Calculator::inputstream_get(char& ch)
{
++inputpos;
return input->get(ch) ? this : nullptr;
}
This preserves the semantics of returning a null pointer on failure, and an unspecified non-null pointer on success.
To answer your last question. You cannot cast a non pointer to a pointer. But you can cast any pointer to a void pointer with (void*)
This is the deal. http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool
In C++03 that was operator void* and in C++11 that is operator bool.
Change that void* to bool. Note that after the change the code will be not usable in C++03 compiler. You can solve it in a portable fashion with
if (input->get(ch)) return true;
else return false;
Actually, the most proper way is to return reference to the actual istream object.
In following code:
if ( cin >> x ) { /* ... */ }
the standard library define an operator conversion operator void*, which converts type istream to void*. However, if the if tests a condition, why the standard library doesn't define a conversion from type istream to type bool? Or is there any implicit consideration behind the implementation?
The simple reason is that you don't want to accidentally end up with a conversion to an int. For example, assume there is an implicit conversion to bool and you wrote
if (std::cin << x) { /* ... */ }
The compiler couldn't catch the obvious error (using << instead of >>) because the implicit conversion would convert to int and happily shift the result. That is almost certainly not what is intended. A void* can't be shifted, i.e., the compiler would yield an error instead.
Prior to C++11 there was no way to mark conversion operators explicit. You could only mark conversion constructors as explicit. In C++11 the conversion operator for streams was actually changed to an explicit conversion to bool as the conversion to void* had a few problems, too.
The operator bool() has always been a bit problematic. The main problem is that bool in C++ is an arithmetic operator, so any class that implements operator bool() will automatically be convertible to int.
Thus, the following code would be legal, but quite meaningless:
cout << (2 * cin);
The designers of the standard library thought that the operator less likely to cause problem, while at the same time being able to be converted to bool would be operator void*. The idea is that a void*, as is, cannot be used for anything.
That said, other more modern libraries, such as boost sometimes use the following idiom:
typedef void *this_type::*unspecified_bool_type;
operator unspecified_bool_type() const { return ... ; }
That is, instead of bool or void* they use a pointer-to-member-function, that will be truly useless other than being converted to bool.
That said, with C++11, the designers of the language noticed this problem and designed the following solution:
explicit operator bool() const
{ return ...; }
Now, this operator will only be called when the object is in a truly bool context (if, while...) , not in any random integral operation.
While looking at legacy code I found something similar to the following code
void* legacy_type::operator new(size_t size) {
return pool_alloc(size);
}
pool_alloc is known to never throw and return 0 in case of failure.
There is no overload for std::nothrow variant of new here.
I wonder whether this code is semantically correct and has well defined behavior.
Should new (std::nothrow) legacy_type; use custom pool_alloc? In my compiler it does not compile at all. Is it well defined behavior?
Should constructor run and crash due to this==0 if overloaded operator new returns zero? In my compiler it runs (and crashes on member initialization). Is it standard well defined behavior?
1) No it shouldn't. These are different functions. And, when you overload one of the operations - all other operations will never work, if they are not overloaded, since if there is operator new in class-scope and signature is not acceptable, then compiler will not search for global operator new, so, compile-error will happened.
2) You break postconditions, if your new will return null pointer.
n3376 18.6.1.1/3
Required behavior: Return a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_-
alloc exception. This requirement is binding on a replacement version of this function.
If you want to returns 0, you should use following signature
void* operator new(size_t) throw()
if you use this overloading and returns 0 from it, there is no seg-fault.
n3376 5.3.4/13
If the
allocation function returns null, initialization shall not be done, the deallocation function shall not be called,
and the value of the new-expression shall be null.
a code like
cin>> grade;
where grade is a standard data type returns a reference to cin(istream object) which enables cascaded inputs....
but i read that if
cin >>grade;
is used as a condition say in a while statement...the stream's void* cast operator function is called implicitly...and it converts reference to istream object into a non-null or null pointer depending upon success or failure of last input operation...and null pointer converts to false and non-null to true...my questions are:
what is the void * cast operator function and how does it work here
how is non-null pointer converted to true and null to false
1.what is the void * cast operator function and how does it work here
It looks something like this:
operator void* () const {
return fail() ? 0 : this;
}
The question is: why isn’t an operator bool used here? The answer is: because that allows invalid conversions which may hide bugs. The above is an example of the safe bool idiom.
However, this implementation is actually obsolete. There exist better implementations of this idiom; the article explains them.
2.how is non-null pointer converted to true and null to false
This is just how C++ works: any non-null pointer is considered equivalent to true in a conditional. Now, why does C++ invoke the operator void* here in the first place?
Essentially, when C++ sees an object of an unexpected type, it tries to apply one implicit conversion that would make the object type valid in this context. The compiler therefore tries out all available implicit conversions and looks whether the resulting type would be acceptable in this context.
This is happening her: the compiler sees while (cin >> grade). It knows that basic_istream isn’t valid in the context of a while conditional. So it finds that there is an operator void*, and a void* is valid in this context so C++ applies this conversion.
I transferred my code to Ubuntu 4.4.1 g++ compiler. While overloading operator ++ (int) as below, it throws error for (T*), but works fine for (T*&). In my earlier version (linux-64, but don't remember exact version) it was working fine with (T*) also.
Any reason, why ?
template<typename T>
struct Wrap
{
void *p; // Actually 'p' comes from a non-template base class
Wrap<T>& operator ++ ()
{
((T*)p) ++; // throws error; if changed to (T*&) then ok!
return *this;
}
// ...
};
int main ()
{
Wrap<int> c;
++c; // calling prefix increment
}
A result of a type-cast is not an lvalue, so it cannot be assigned to and (built-in) ++ is a form of assignment. It was a bug in the compiler if it ever worked.
With reference it compiles (in efect it's the same as *(T**)&p), but due to aliasing rules (compiler may assume that pointers (and references) of different types don't point to the same object) it is formally invalid, though it will work on all known compilers.
The cleanest way it to:
p = static_cast<void *>(static_cast<T *>(p) + 1)
(never use C-style cast in C++) and rely on the compiler being able to compile it exactly the same way as ++. However if you have the template argument available when defining the pointer (in the sample code you do), it's much better to just use properly typed pointer (I'd say it would also work with member pointers, but they don't have meaningful ++).
Looks like you mixing up your prefix and postfix increment signatures. Also, why use a void* if you know your type is T ?
See below for appropriate signatures:
http://www.codeguru.com/forum/showthread.php?t=231051