What are all operations supported by function pointer differs from raw pointer? Is > , < , <= , >=operators supported by raw pointers if so what is the use?
views:
398answers:
6#1: Function pointers can be invoked.
#2:The relational operators are supported for pointers because you can use them in pointer arithmetics and compare addresses to each other. Practical example: Traversing an array
int data[5] = { 1, 2, 3, 4, 5 };
// Increment pointer until it reaches the end-address.
for (int* i = data; i < data + 5; ++i) {
std::cout << *i << endl;
}
You can compare pointers if they point into the same allocation. For example, if you have two pointers pointing at elements of the same array, you can use inequality comparison operators on those pointers. On the other hand, if you have two pointers pointing at different objects, then comparison is "undefined", though, in practice, most compilers will probably just compare the addresses.
char *text[] = "hello";
const char *e_ptr = strchr(text, 'e');
const char *o_ptr = strchr(text, 'o');
if (e_ptr < o_ptr) { ... } // this is legal
char *other_text[] = "goodbye";
const char *b_ptr = strchr(other_text, 'b');
if (b_ptr > o_ptr) { ... } // not strictly legal
The operators <, >, <=, >= are supported for pointers, but are only guaranteed to produce reliable results if the two pointers being compared are part of the same memory allocation (like comparing two pointers to indexes in an array allocation). For these, it indicates relative position in the allocation (ie, if a < b, then a is pointing to a lower index in the array than b). For pointers that are not in the same allocation, the result is implementation defined (and in some architectures, can violate strict less than compatibility needed for maps. For instance, a 64-bit pointer could be compared for < or > using only the lower 32 bits, if an single allocation cannot exceed the size allowed for a 32-bit pointer). These don't really make sense in the context of function pointers since they don't address a continuous memory allocation.
Other raw pointer operations: == returns true if the pointers are pointing to the same object. - produces the number of bytes between the two pointers (I think good for the same allocation only?). + doesn't compile, as it would be meaningless.
For function pointers, they can be dereferenced by * and called.
For pointer-to-member-functions, there are the operators ->* and .*
For both function and object pointers, they compile but their result is only guaranteed to be consistent for addresses to sub-objects of the same complete object (you may compare the addresses of two members of a class or array) and if you compare a function or object against itself.
Using std::less<>
, std::greater<>
and so on will work with any pointer type, and will give consistent results, even if the result of the respective built-in operator is unspecified:
void f() { }
void g() { }
int main() {
int a, b;
///// not guaranteed to pass
assert((&a < &b) == (&a < &b));
///// guaranteed to pass
std::less<int*> lss1;
assert(lss1(&a, &b) == lss1(&a, &b));
// note: we don't know whether lss1(&a, &b) is true or false.
// But it's either always true or always false.
////// guaranteed to pass
int c[2];
assert((&c[0] < &c[1]) == (&c[0] < &c[1]));
// in addition, the smaller index compares less:
assert(&c[0] < &c[1]);
///// not guaranteed to pass
assert((&f < &g) == (&f < &g));
///// guaranteed to pass
assert((&g < &g) == (&g < &g));
// in addition, a function compares not less against itself.
assert(!(&g < &g));
///// guaranteed to pass
std::less<void(*)()> lss2;
assert(lss2(&f, &g) == lss2(&f, &g));
// note: same, we don't know whether lss2(&f, &g) is true or false.
///// guaranteed to pass
struct test {
int a;
// no "access:" thing may be between these!
int b;
int c[1];
// likewise here
int d[1];
test() {
assert((&a < &b) == (&a < &b));
assert((&c[0] < &d[0]) == (&c[0] < &d[0]));
// in addition, the previous member compares less:
assert((&a < &b) && (&c[0] < &d[0]));
}
} t;
}
Everything of that should compile though (although the compiler is free to warn about any code snippet it wants).
Since function types have no sizeof
value, operations that are defined in terms of sizeof
of the pointee type will not work, these include:
void(*p)() = ...;
// all won't work, since `sizeof (void())` won't work.
// GCC has an extension that treats it as 1 byte, though.
p++; p--; p + n; p - n;
The unary +
works on any pointer type, and will just return the value of it, there is nothing special about it for function pointers.
+ p; // works. the result is the address stored in p.
Finally note that a pointer to a function pointer is not a function pointer anymore:
void (**pp)() = &p;
// all do work, because `sizeof (void(*)())` is defined.
pp++; pp--; pp + n; pp - n;
A pointer is represented as a normal integer value. You can do everything with pointers which is also allowed on all other numeric types. + - * / << >> == != ^ & | ! ~ %. I hope I forgot nothing.
A function pointer is only different in that way that it can be called with the () operator.
Using std::less<>, std::greater<> and so on will work with any pointer type, and will give consistent results, even if the result of the respective built-in operator is unspecified:
Does anyone have a reference for that? I didn't find this in Stroustrup's "The C++ Programming Language", Special Ed., nor at http://www.cplusplus.com/reference/std/functional/less/. Also checking the header files of my local compiler installation (g++ 4.4.1) showed that the std::less<> template is simply defined in terms of the < operator. Have I missed something?