I'm reading the code of ROS.
In the file ros_comm/roscpp/include/ros/subscriber.h, I see such a piece of code:
operator void*() const { return (impl_ && impl_->isValid()) ? (void*)1 : (void*)0; }
Well, (void *)0 can be regarded as NULL in C, but what does (void *)1 mean?
If a class Foo contains this function, it means that we can code like this:
Foo foo;
void *ptr = foo;
Right? So does it mean that void *ptr = (void *)1 is possible? What does this mean?
This is an old trick to avoid problems with implicit conversions to bool from before explicit contextual conversions were introduced in C++11. It's intended to be used to check validity:
Subscriber my_subscriber = someFunction();
if (!my_subscriber) {
// error case
}
The important point is that no built-in conversion exists from void* to integer types, but one does exist from bool to integer types. At the same time, a built-in conversion from void* to bool exists. That means that if you define an implicit conversion to bool, then the following is surprisingly valid:
void my_func(int i);
void another_func() {
Subscriber sub = something();
my_func(sub);
}
Defining a conversion to void* avoids that issue.
These days that trick is obsolete though. C++11 introduced explicit conversions. explicit conversions to bool are considered in the conditions of if and loops, but aren't considered in other problematic cases. That means that these days that conversion should be written as:
explicit operator bool() const { return impl_ && impl_->isValid(); }
It shows that either the person who wrote the code isn't very well acquainted with the language or tools they're using, or the code has been around for a long, long time and been hacked on by different people, presumably having undergone a C-to-C++ transition at some time in the past, still carrying some legacy API contract (expecting a void*) which may be troublesome to change.
There is no good reason to do such a thing, if you look at the source. impl_ is a boost::shared_ptr<Impl> which implements operator bool, and Impl::isValid returns bool, too. There's no reason to use, or return anything but bool anywhere.
Basically, this is a contorted (and possibly dangerous) way of writing:
return impl_ && impl_->isValid();
Related
Think in a similar fashion like:
1. The bare name of an array is equivalent with the pointer to the first element, without the need to specify index 0.
2. toString() from Java makes it possible to use the name of an object as a string without calling any object method.
Now is there a way in C++ to use the name of a class object to refer to its first member?
Consider:
class Program
{
public:
int id;
char *str;
};
void function(int p)
{
//...
}
and then:
Program prog0;
function(prog0); // instead of function(prog0.id)
Any way to "hide" the member reference?
EDIT:
Why was the holyBlackCat's answer deleted? I was inclining to vote it as the best answer -- no offense, Mateusz. But he was the first to suggest conversion operator and the example was complete and simple.
In C++, such behaviour would be a cataclysm. If I understand correctly, Java tries to convert object of type A to object of type B by searching for first member in A, that is of type B or is implicitly convertible to B.
C++ wasn't designed that way. We like to write code, that is always predictable. You can achieve what you want, but for a price.
The best solution in this case would be conversion operator - consider:
class Program
{
public:
int id;
char *str;
operator int()
{
return this->id;
}
//You can have more than one!
operator const char*()
{
return this->str;
}
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}
Now it is possible to do the following:
Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)
The price is, that if you add another int and place it before id it will not be used in conversion, because we stated in our operator explicitly, that "int content" of our class is represented by id and this member is considered when it comes to such conversion.
However, even this simple example shows some potential problems - overloading functions with integral and pointer types could result in very unpredictable behavior. When type contains conversion operators to both pointers and integers, it can get even worse.
Assume, that we have following function:
void func(unsigned long)
{
}
And we call func with argument of type Program. Which conversion operator would you expect to be called? Compiler knows how to convert Program to either int or const char*, but not unsigned long. This article on cppreference should help you to understand how implicit conversions work.
Also, as Barry pointed out, more meaningless constructs become available. Consider this one:
int x = prog + 2
What does it mean? It is perfectly valid code, though. That is why conversion operators should be dosed extremely carefully (in pre-C++11 era, there was a general advise, that every class should have at most one such operator).
Quote from MSDN:
If a conversion is required that causes an ambiguity, an error is generated. Ambiguities arise when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.
Sometimes, simple solution to this problem is to mark conversion operator with explicit keyword, so you would need to change above calls to:
function_int((int)prog);
function_str((const char*)prog);
It is not as pretty as the previous form, but much safer. It basically means, that compiler is forbidden to perform any implicit conversion using operator marked as explicit. Very useful to avoid ambiguous calls, while still providing some flexibility in code - you can still very easily convert objects of one type to another, but you can be sure when and where these conversions are performed.
However, explicit conversion operators are still not supported by some compilers, as this is C++ 11 feature (for example, Visual C++ 11 doesn't support it).
You can read more about explicit keyword here.
Now is there a way in C++ to use the name of a class object to refer to its first member?
No, C++ doesn't have any reflection, so there's no way to actually determine what the "first member" is.
However, if what you really want is to get an ID for any object, you could just require that object to have that method:
template <typename T>
void function(const T& t) {
int id = t.getID();
// etc.
}
Without knowing more about your use-case, it's hard to know what to propose.
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.
Horstmann’s C++ pitfalls tackles an interesting point when talking about streams. To quote him:
Use conversion to void*, not conversion to int or bool, to implement objects yielding truth values. Unlike int or bool, void* have no legal operations other than == comparison.
As a programmer, I would be puzzled if some function returned void* when I expect a boolean. Horstmann provides an example where using a void* instead of a bool seems appropriate. Is it always advisable?
This is not advised in general circumstances and, with C++11, is not advised at all.
The reason for the conversion to void* was to support syntax like
std::ifstream myStream;
if (myStream) {
}
if (!myStream) {
}
Here, a conversion to bool seems more reasonable, but leads to weirdnesses like this:
if (myStream == true) // ??
The conversion to void* prevents this code from being legal, but opens up a whole other can of worms, like
delete myStream; // ??
In C++11, with the ability to have explicit operator bool() as a member function, this void* hack is deprecated and should not be used. Don't use this idiom. If you need something to return a bool, have it return a bool. If you need an object that can be converted to a bool, use explicit operator bool.
Hope this helps!
I was looking into how std::tr1::shared_ptr<> provides the ability to cast to bool. I've got caught out in the past when trying to create a smart pointer that can be casted to bool as the trivial solution, ie
operator bool() {
return m_Ptr!=0;
}
usually ends up being implicitly castable to the pointer type (presumably by type promotion), which is generally undesirable. Both the boost and Microsoft implementations appear to use a trick involving casting to an unspecified_bool_type(). Can anyone explain how this mechanism works and how it prevents implicit casting to the underlying pointer type?
The technique described in the question is the safe bool idiom.
As of C++11, that idiom is no longer necessary. The modern solution to the problem is to use the explicit keyword on the operator:
explicit operator bool() {
return m_Ptr != nullptr;
}
The trick works like this. You define all this inside your smart pointer type (in this case, shared_ptr):
private:
struct Tester
{
Tester(int) {} // No default constructor
void dummy() {}
};
typedef void (Tester::*unspecified_bool_type)();
public:
operator unspecified_bool_type() const
{
return !ptr_ ? 0 : &Tester::dummy;
}
ptr_ is the native pointer inside the smart pointer class.
As you can see, unspecified_bool_type is a typedef to a type that cannot be accessed by any external code, since Tester is a private struct. But calling code can use this (implicit) conversion to a pointer type and check whether it is null or not. Which, in C++, can be used as a bool expression.
Usually what it returns is a member pointer. Member pointers can be treated like a bool but don't support many of the implicit conversions which bool does.
I understand that the keyword explicit can be used to prevent implicit conversion.
For example
Foo {
public:
explicit Foo(int i) {}
}
My question is, under what condition, implicit conversion should be prohibited? Why implicit conversion is harmful?
Use explicit when you would prefer a compiling error.
explicit is only applicable when there is one parameter in your constructor (or many where the first is the only one without a default value).
You would want to use the explicit keyword anytime that the programmer may construct an object by mistake, thinking it may do something it is not actually doing.
Here's an example:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
With the following code you are allowed to do this:
int age = 29;
//...
//Lots of code
//...
//Pretend at this point the programmer forgot the type of x and thought string
str s = x;
But the caller probably meant to store "3" inside the MyString variable and not 3. It is better to get a compiling error so the user can call itoa or some other conversion function on the x variable first.
The new code that will produce a compiling error for the above code:
class MyString
{
public:
explicit MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
Compiling errors are always better than bugs because they are immediately visible for you to correct.
It introduces unexpected temporaries:
struct Bar
{
Bar(); // default constructor
Bar( int ); // value constructor with implicit conversion
};
void func( const Bar& );
Bar b;
b = 1; // expands to b.operator=( Bar( 1 ));
func( 10 ); // expands to func( Bar( 10 ));
A real world example:
class VersionNumber
{
public:
VersionNumber(int major, int minor, int patch = 0, char letter = '\0') : mMajor(major), mMinor(minor), mPatch(patch), mLetter(letter) {}
explicit VersionNumber(uint32 encoded_version) { memcpy(&mLetter, &encoded_version, 4); }
uint32 Encode() const { int ret; memcpy(&ret, &mLetter, 4); return ret; }
protected:
char mLetter;
uint8 mPatch;
uint8 mMinor;
uint8 mMajor;
};
VersionNumber v = 10; would almost certainly be an error, so the explicit keyword requires the programmer to type VersionNumber v(10); and - if he or she is using a decent IDE - they will notice through the IntelliSense popup that it wants an encoded_version.
Mostly implicit conversion is a problem when it allows code to compile (and probably do something strange) in a situation where you did something you didn't intend, and would rather the code didn't compile, but instead some conversion allows the code to compile and do something strange.
For example, iostreams have a conversion to void *. If you're bit tired and type in something like: std::cout << std::cout; it will actually compile -- and produce some worthless result -- typically something like an 8 or 16 digit hexadecimal number (8 digits on a 32-bit system, 16 digits on a 64-bit system).
At the same time, I feel obliged to point out that a lot of people seem to have gotten an almost reflexive aversion to implicit conversions of any kind. There are classes for which implicit conversions make sense. A proxy class, for example, allows conversion to one other specific type. Conversion to that type is never unexpected for a proxy, because it's just a proxy -- i.e. it's something you can (and should) think of as completely equivalent to the type for which it's a proxy -- except of course that to do any good, it has to implement some special behavior for some sort of specific situation.
For example, years ago I wrote a bounded<T> class that represents an (integer) type that always remains within a specified range. Other that refusing to be assigned a value outside the specified range, it acts exactly like the underlying intger type. It does that (largely) by providing an implicit conversion to int. Just about anything you do with it, it'll act like an int. Essentially the only exception is when you assign a value to it -- then it'll throw an exception if the value is out of range.
It's not harmful for the experienced. May be harmful for beginner or a fresher debugging other's code.
"Harmful" is a strong statement. "Not something to be used without thought" is a good one. Much of C++ is that way (though some could argue some parts of C++ are harmful...)
Anyway, the worst part of implicit conversion is that not only can it happen when you don't expect it, but unless I'm mistaken, it can chain... as long as an implicit conversion path exists between type Foo and type Bar, the compiler will find it, and convert along that path - which may have many side effects that you didn't expect.
If the only thing it gains you is not having to type a few characters, it's just not worth it. Being explicit means you know what is actually happening and won't get bit.
To expand Brian's answer, consider you have this:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
// ...
};
This actually allows this code to compile:
MyString mystr;
// ...
if (mystr == 5)
// ... do something
The compiler doesn't have an operator== to compare MyString to an int, but it knows how to make a MyString out of an int, so it looks at the if statement like this:
if (mystr == MyString(5))
That's very misleading since it looks like it's comparing the string to a number. In fact this type of comparison is probably never useful, assuming the MyString(int) constructor creates an empty string. If you mark the constructor as explicit, this type of conversion is disabled. So be careful with implicit conversions - be aware of all the types of statements that it will allow.
I use explicit as my default choice for converting (single parameter or equivalent) constructors. I'd rather have the compiler tell me immediately when I'm converting between one class and another and make the decision at that point if the conversion is appropriate or instead change my design or implementation to remove the need for the conversion completely.
Harmful is a slightly strong word for implicit conversions. It's harmful not so much for the initial implementation, but for maintenance of applications. Implicit conversions allow the compiler to silently change types, especially in parameters to yet another function call - for example automatically converting an int into some other object type. If you accidentally pass an int into that parameter the compiler will "helpfully" silently create the temporary for you, leaving you perplexed when things don't work right. Sure we can all say "oh, I'll never make that mistake", but it only takes one time debugging for hours before one starts thinking maybe having the compiler tell you about those conversions is a good idea.