I have been recently learning how to use the std::mem_fn library facility. In C++ Primer 5th edition they give an example of a usage of std::mem_fn, in the following code snippet svec is a vector of strings:
auto f = mem_fn(&string::empty); // f takes a string or a string*
f(*svec.begin()); // ok: passes a string object; f uses .* to call empty
f(&svec[0]); // ok: passes a pointer to string; f uses .-> to call empty
Note: In the above code snippet there is no use of ->*
Although I understand the usage .* and ->*. I don't have clarity on it.
So, My question is what does .*, ->*, .-> do?
You have an object o and a pointer to its member m. The operator .* allows you to access the pointed member of your object:
o.*m
You have a pointer to an object p and a pointer to its member m. The operator ->* allows you to access the pointed member of the pointed object:
p->*m
I am afraid that the operator .-> doesn't exist.
Operators .* and ->* call a member function (BTW there is no meaning for .-> in C++ - it's a syntax error).
These are binary operators. The left operand is an object (for .*) or a pointer to an object (for ->*), and the right operand is a pointer to a member (which can be a member field or a member function). The outcome of applying this operator is the ability to use a member field or a method.
Maybe these operators make sense from a historical point of view. Suppose you use a regular C pointer to a function:
typedef int (*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &CalcResult42;
...
int result = my_calc_func(11, 22, 33);
What if you decided to "rewrite" your program in an object-oriented way? Your calculation function would be a method in a class. To make a pointer to it, you need a new type, a pointer to member function:
typedef int (MyClass::*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object;
int result = (my_object.*my_calc_func)(11, 22, 33);
I always use this analogy when I try to remember the syntax of this .* operator - this helps because the regular pointer-to-function syntax is less convoluted and used more frequently.
Please note the parentheses:
int result = (my_object.*my_calc_func)(11, 22, 33);
They are almost always needed when using this .* operator, because its precedence is low. Even though my_object .* (my_calc_func(11, 22, 33)) is meaningless, the compiler would try to make sense of it if there were no parentheses.
The ->* operator works in essentially the same way. It would be used if the object on which to apply the method is given by a pointer:
typedef int (*MyClass::CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object1, my_object2;
MyClass* my_object = flag ? &my_object1 : &my_object2;
int result = (my_object->*my_calc_func)(11, 22, 33);
The .* and ->* operators are called pointer to member access operators and like their name suggests they allow you to access an object's data or function member given an appropriate pointer to that class member.
struct foo
{
int a;
float b;
void bar() { std::cout << "bar\n"; }
};
int main()
{
int foo::* ptra = &foo::a;
float foo::* ptrb = &foo::b;
void (foo::* ptrbar)() = &foo::bar;
foo f;
foo * fptr = &f;
f.*ptra = 5;
f.*ptrb = 10.0f;
(f.*ptrbar)();
fptr->*ptra = 6;
fptr->*ptrb = 11.0f;
(fptr->*ptrbar)();
return 0;
}
Related
I am a C++ noob and I am quite sure this is a stupid question, but I just do not quite understand why an error arises (does not arise) from the following code:
#include <iostream>
using namespace std;
int main()
{
int a,*test;
*test = &a; // this error is clear to me, since an address cannot be
// asigned to an integer
*(test = &a); // this works, which is also clear
return 0;
}
But why does this work too?
#include <iostream>
using namespace std;
int main()
{
int a, *test= &a; // Why no error here?, is this to be read as:
// *(test=&a),too? If this is the case, why is the
// priority of * here lower than in the code above?
return 0;
}
The fundamental difference between those two lines
*test= &a; // 1
int a, *test= &a; // 2
is that the first is an expression, consisting of operator calls with the known precedence rules:
operator=
/\
/ \
/ \
operator* operator&
| |
test a
whereas the second is a variable declaration and initialization, and equivalent to the declaration of int a; followed by:
int* test = &a
// ^^ ^^ ^^
//type variable expression giving
// name initial value
Neither operator* nor operator= is even used in the second line.
The meaning of the tokens * and = (and & as well as ,) is dependent on the context in which they appear: inside of an expression they stand for the corresponding operators, but in a declaration * usually appears as part of the type (meaning "pointer to") and = is used to mark the beginning of the (copy) initialization expression (, separates multiple declarations, & as "reference to" is also part of the type).
int a, *test= &a;
is equivalent of:
int a;
int* test = &a;
and perfectly valid as you initialize test which has a type of pointer to int with an address of variable a which has a type of int.
You're confusing two uses for *.
In your first example, you're using it to dereference a pointer.
In the second example, you're using it to declare a "pointer to int".
So, when you use * in a declaration, it's there to say that you're declaring a pointer.
You are actually doing an initialisation like this in first case,
int *test = &a;
It means that, you are initialising a pointer for which you mention * to tell the compiler that its a pointer.
But after initialisation doing a *test (with an asterisk) means that you are trying to access the value at the address assigned to pointer test.
In other words, doing an *test means you are getting the value of a because address of a is stored into pointer test which is done by just doing a &a.
& is the operator to get the address of any variable. And * is the operator to get the value at address.
So initialisation & assignment are inferred differently by the compiler even if the asterisk * is present in both the cases.
You just hit two of the horrible language design spots: squeezing declarations into one line and reuse of * symbol for unrelated purposes. In this case * is used to declare a pointer (when it is used as part of type signature int a,*test;) and to deference a pointer (when it is used as a statement *test = &a;). The good practice would be to declare variables one at a time, to use automatic type deduction instead of type copypasting and to use dedicated addressof method:
#include <memory> // for std::addressof
int a{};
auto const p_a{::std::addressof(a)};
There's a subtle difference there.
When you declare int a, *test, you're saying "declare a as an integer, and declare test as a pointer to an integer, with both of them uninitialized."
In your first example, you set *test to &a right after the declarations. That translates to: "Set the integer that test points to (the memory address) to the address of a." That will almost certainly crash because test wasn't initialized, so it would either be a null pointer or gibberish.
In the other example, int a, *test= &a translates to: "declare a as an uninitialized integer, and declare test as a pointer initialized to the address of a." That's valid. More verbosely, it translates to:
int a, *test;
test = &a;
I understand my second statement that "why & is not needed for normal function pointers" because function name itself is address of the function.
What I do not understand is why '&' is strictly needed for member function pointers?
Examples:
Normal function pointers:
int add(int a, int b) {
return (a + b);
}
int (*fp)(int, int);
fp = add;
(*fp)(2, 3) // This would give me addition of a and b, i.e. 5
Member function pointers:
class ABC {
public:
int i;
ABC() { i = 0; }
int addOne(int j) {
return j + 1;
}
};
// Member function pointer
int (ABC::*mfp)(int);
// This is what I am talking about. '&' in below line.
mfp = &ABC::addOne;
ABC abc;
std::cout << (abc.*mfp)(2) << std::endl;
It seems to me that the address-of operator is necessary for member function pointers because the right-hand side (rhs) of the declaration is a constant rather than a variable.
We wouldn't say
int (ABC::*mfp)(int);
mfp = ABC::addOne();
because that would be to invoke a function.
Furthermore, the scope resolution operator :: has the highest precedence in the C++ table of operator precedence:
https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/cpp-built-in-operators-precedence-and-associativity.md
The :: operator is evaluated before any other operators are on the rhs. I suppose the complier wonders "Hmmmm...what's that? That should be a function, but..." and then sees the address-of operator and knows what the developer needs.
This question already has answers here:
-> usage in smart pointers
(2 answers)
Closed 9 years ago.
smart pointers like shared_ptr can be used like ordinary pointers with * and -> operator.
The books say that -> operator returns the pointer that shared_ptr stores. So you can use it to access the object this pointer points to. But I am confused here. Look at the code below.
class A
{
public:
A(int v = 20){val = v;}
int val;
}
A* p1 = new A;
std::cout<<p1->val; //This is common sense
boost::shared_ptr<A> p2(new A);
std::cout<<p2->val; //This is right
//My question is that p2-> returns the pointers of the object, then maybe another
//-> should be used?
//like (p2->)->val?
It's magic. Well, more like a special case. The standard says that
13.5.6 Class member access [over.ref]
1 operator-> shall be a non-static member function taking no parameters. It implements the class member access syntax that uses ->.
postfix-expression -> templateopt id-expression
postfix-expression -> pseudo-destructor-name
An expression x->mis interpreted as (x.operator->())->m for a class object x of type T if T::operator->()
exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3).
That is, operator-> is called again on the result of the overloaded operator. And if that one is overloaded too, it goes on recursively until a raw pointer is the result and the built-in operator-> is called.
That doesn't mean the result can't be any arbitrary type - it can be, but then you can only call it with the function call syntax:
struct X {
int operator->() { return 42; }
};
int main()
{
X x;
x.operator->(); // this is OK
}
Fortunately, designers of C++ realized this, and changed the semantics of the overloaded infix -> operator to mean that the pointer returned by your operator is plugged in on the left-hand side of the -> operator, and then the member is accessed as usual.
If you were to invoke the -> operator explicitly, you would need to insert an additional ->, though:
std::cout << p1.operator->()->val;
Demo on ideone.
The return value of operator -> is not the same as what p2->val returns. The return value of operator -> is a pointer that will be used to access the val member, so p2->val works as expected.
I can overload the parenthesis operator using the following signature:
char& operator()(const int r, const int c);
The intended usage of this would be:
// myObj is an object of type MyClass
myObj(2,3) = 'X'
char Y = myObj(2,3);
Which works as I expect. However, using the parenthesis operator when dealing with a pointer becomes convoluted. I would like to do:
// pMyObj is a pointer to an object of type MyClass
pMyObj->(2,3) = 'X';
char Y = pMyObj->(2,3);
However, such syntax yields the error Error: expected a member name (in VisualStudio at least).
The following does work but seems convoluted to me with a dereference and more parentheses than arguments.
char X = (*pMyObj)(2,3);
Is there a way to use the -> operator to call the () overload?
Yes there is, but you won't like it:
pMyObj->operator()(2,3);
You could also create a reference to the pointed to object and do
MyObj& rMyObj = *pMyObj;
char Y = rMyObj(2, 3);
which might be a good alternative if your code will be read by people who could be confused by
pMyObj->operator()(2,3);
if you do as below
#define SUB operator()
Then you can write things like this ...
pMyObj->SUB(2,3)
not as elegant as Fortran ;-) but perhaps not too ugly for actual use
If I have a pointer to an object that has an overloaded subscript operator ([]) why can't I do this:
MyClass *a = new MyClass();
a[1];
but have to do this instead:
MyClass *a = new MyClass();
(*a)[1];
It's because you can't overload operators for a pointer type; you can only overload an operator where at least one of the parameters (operands) is of class type or enumeration type.
Thus, if you have a pointer to an object of some class type that overloads the subscript operator, you have to dereference that pointer in order to call its overloaded subscript operator.
In your example, a has type MyClass*; this is a pointer type, so the built-in operator[] for pointers is used. When you dereference the pointer and obtain a MyClass, you have a class-type object, so the overloaded operator[] is used.
Because a is type pointer to a MyClass and not a MyClass. Changing the language to support your desired use would make many other language semantics break.
You can get the syntactic result you want from:
struct foo {
int a[10];
int& operator [](int i) { return a[i]; }
};
main() {
foo *a = new foo();
foo &b = *a;
b[2] = 3;
}
Good news. You can also do...
a->operator[](1);
To add on to the preferred answer, think of operator overloading as overloading functions.
When overloading member function of a class, you remember that the pointer is not of that class type.
Simply put, with a[1] the a pointer is treated as memory containing array, and you're trying to access the 2nd element in the array (which doesn't exist).
The (*a)[1] forces to first get the actual object at the pointer location, (*a), and then call the [] operator on it.