Is operator-> "chained" for pointers? [duplicate] - c++

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Overloading operator ->
Hi,
I've seen that operator->() is chained (re-applied) after it is evaluated, for example:
struct Bar
{
Bar() : m_str("Hello world!") {}
const string* operator->() const { return &m_str; }
string m_str;
};
struct Foo
{
const Bar& operator->() const { return m_bar; }
Bar m_bar;
};
int main()
{
Foo f;
cout << f->c_str() << endl;
return 0;
}
works pretty fine, which requires three operator->() to be evaluated - Foo::operator->(), Bar::operator->() and regular pointer resolution.
But it wont work with pointers in the middle - if Foo::operator->() returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>> for example.
Is it specific to non-overloaded operator->() so it is only applied once and does not cause chaining?
Is it possible to make code below works without using (*ptr2)-> ...?
int main()
{
string s = "Hello world";
auto_ptr<string> ptr1(&s);
auto_ptr<auto_ptr<string> > ptr2(&ptr1);
cout << ptr1->c_str() << endl; // fine
cout << ptr2->c_str() << endl; // breaks compilation
}
Thanks!

C++98 standard §13.5.6/1 "Class member access":
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).
What this means in practice is that when x is a pointer, you don’t get chaining; you then just get the built-in operator-> (i.e. x->m with x a pointer translates to (*x).m).
But when x is an object of class type T, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m can be that (x.operator->()) itself is an object of some class, say class U. Whence the second -> can be resolved as U::operator->, and so on, if the result of that again is a class type object…
Like, in your case, Foo::operator-> produces (a reference to) an object of class Bar, which does define an operator->.
But when operator-> returns a pointer, as e.g. std::auto_ptr<T>::operator-> does, then it's just the built-in operator-> that's used.
In passing, the chaining can be used to practically prevent someone from using delete inappropriately. std::auto_ptr does not do that. And I’ve never seen it done.
But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.
Cheers & hth.

The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr you actually are returned a real pointer and the default operator -> is invoked for regular pointers.
Please see the Overloading operator -> question for more details.

No, it is not possible for it to work. If you could overload operator -> for string * you could make it work. But operator -> already has a definition for all pointer types. So, just like you can't overload + for primitive numeric types, you can't overload operator -> for any pointer type.
And even if you could, how could the compiler know when the recursion should end?

Related

Why do we return *this in asignment operator and generally (and not &this) when we want to return a reference to the object?

I'm learning C++ and pointers and I thought I understood pointers until I saw this.
On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.
Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.
How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.
For example here:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.
According to the C++ 17 Standard (8.1.2 This)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
Consider the following code snippet as an simplified example.
int x = 10;
int *this_x = &x;
Now to return a reference to the object you need to use the expression *this_x as for example
std::cout << *this_x << '\n';
& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.
In C++, after a type name, it also means that what follows is a reference to an object of this type.
This means that is you enter :
int a = 0;
int & b = a;
… b will become de facto an alias of a.
In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.
Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.
&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.
It would make more sense to ask why we don't do return this;.
The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:
int x = 42;
int *ptr = &x;
int &ref = x;
So, similarly:
int *f1() return {return &x;}
int &f1() return {return x;}
A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:
* converts a foo* to a foo&
& converts a foo& to a foo*
In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.
C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.
References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.
The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.

Regarding definition of dereferencing and member selection operators in smart pointer

In smart pointer implementation, dereferencing operator and member selection operators are always defined as below.
T& operator* () const // dereferencing operator
{
return *(m_pRawPointer);
}
T* operator->() const // member selection operator
{
return m_pRowPointer;
}
I don't quite understand why the former is returned by reference, the latter is returned by pointer. Is it just to differentiate them or some other reasons?
To be more specific, can I make dereferencing operator returns by pointer, while the other one returns by reference?
why the former is returned by reference
So that the expression *thing gives an lvalue denoting an object of type T, just as it would if thing were a pointer.
the latter is returned by pointer
Because that's how the language is specified. Note that you never use the result of -> directly, but always in an expression of the form thing->member.
If thing is a class type, that's evaluated by calling operator->, then applying ->member to the result of that. To support that, it must return either a pointer, or another class type which also overloads operator->.
can I make dereferencing operator returns by pointer
Yes, but that would be rather confusing since it would behave differently to applying the same operator a pointer. You'd have to say **thing to access the T.
while the other one returns by reference
No, because that would break the language's built-in assumptions about how the overloaded operator should work, making it unusable.
The reason that the dereference operator returns by reference and the member selection operator returns by pointer is to line up the syntax of using a smart pointer with the syntax of using a raw pointer:
int* p = new int(42);
*p = 7;
std::unique_ptr<int> p(new int(42));
*p = 7;
You could absolutely make your dereference operator return anything you like:
struct IntPtr {
int* p;
int* operator*() { return p; }
};
But that would be pretty confusing for your users when they have to write:
IntPtr p{new int{42}};
**p = 7;
The arrow operator is a little different in that [over.ref]:
An expression x->m is interpreted as (x.operator->())->m
So you have to return something on which you can call ->m, otherwise you'll just get an error like (from gcc):
error: result of 'operator->()' yields non-pointer result

the operator-> return value of smart pointers [duplicate]

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.

Function pointer vs Function reference

In the code below, function-pointer and what i considered as "function-reference" seems to have identical semantics:
#include <iostream>
using std::cout;
void func(int a) {
cout << "Hello" << a << '\n';
}
void func2(int a) {
cout << "Hi" << a << '\n';
}
int main() {
void (& f_ref)(int) = func;
void (* f_ptr)(int) = func;
// what i expected to be, and is, correct:
f_ref(1);
(*f_ptr)(2);
// what i expected to be, and is not, wrong:
(*f_ref)(4); // i even added more stars here like (****f_ref)(4)
f_ptr(3); // everything just works!
// all 4 statements above works just fine
// the only difference i found, as one would expect:
// f_ref = func2; // ERROR: read-only reference
f_ptr = func2; // works fine!
f_ptr(5);
return 0;
}
I used gcc version 4.7.2 in Fedora/Linux
UPDATE
My questions are:
Why function pointer does not require dereferencing?
Why dereferencing a function reference doesn't result in an error?
Is(Are) there any situation(s) where I must use one over the other?
Why f_ptr = &func; works? Since func should be decayed into a pointer?
While f_ptr = &&func; doesn't work (implicit conversion from void *)
Functions and function references (i.e. id-expressions of those types) decay into function pointers almost immediately, so the expressions func and f_ref actually become function pointers in your case. You can also call (***func)(5) and (******f_ref)(6) if you like.
It may be preferable to use function references in cases where you want the &-operator to work as though it had been applied to the function itself, e.g. &func is the same as &f_ref, but &f_ptr is something else.
"Why function pointer does not require dereferencing?"
Because the function identifier itself is actually a pointer to the function already:
4.3 Function-to-pointer conversion
§1 An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to the function.
"Why dereferencing a function reference doesn't result in an error?"
Basically you can look at defining a reference as defining an alias (alternative name). Even in the standard in 8.3.2 References in part addressing creating a reference to an object, you will find:
"a reference can be thought of as a name of an object."
So when you define a reference:
void (& f_ref)(int) = func;
it gives you the ability to use f_ref almost everywhere where it would be possible to use func, which is the reason why:
f_ref(1);
(*f_ref)(4);
works exactly the same way as using the func directly:
func(1);
(*func)(4);
See here.
The address-of operator acts like you would expect, as it points to a function but cannot be assigned. Functions are converted to function pointers when used as rvalues, which means you can dereference a function pointer any number of times and get the same function pointer back.
As there are good answers from other people here, there is no answer explaining why f_ptr = &&func; does not work. When you apply the addressof operator & to a variable/function, you get its address. The adress itself is an r-value/a temporary variable. You cannot take the address of a temporary.
But it seems that there is a type error. The message implicit conversion from void* is very compiler specific for this code. I guess you are using GCC/Clang. GCC/Clang offers the ability to take the address of labels like &&label. The resulting value is of type void*. Other compilers will output something like cannot take address of temporary or invalid syntax. When using these compilers this kind of error could have been hidden without any warning in special circumstances:
int main() {
int foo = 42;
foo:;
void* a = &foo; // take the address of a variable/function
void* b = &&foo; // take the address of a label
std::cout << *(int*)a << '\n';
goto *b;
};
But who would name everything the same?

What does -> mean in C++? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
What is the difference between the dot (.) operator and -> in C++?
What is the arrow operator (->) synonym for in C++?
The header says it all.
What does -> mean in C++?
It's to access a member function or member variable of an object through a pointer, as opposed to a regular variable or reference.
For example: with a regular variable or reference, you use the . operator to access member functions or member variables.
std::string s = "abc";
std::cout << s.length() << std::endl;
But if you're working with a pointer, you need to use the -> operator:
std::string* s = new std::string("abc");
std::cout << s->length() << std::endl;
It can also be overloaded to perform a specific function for a certain object type. Smart pointers like shared_ptr and unique_ptr, as well as STL container iterators, overload this operator to mimic native pointer semantics.
For example:
std::map<int, int>::iterator it = mymap.begin(), end = mymap.end();
for (; it != end; ++it)
std::cout << it->first << std::endl;
a->b means (*a).b.
If a is a pointer, a->b is the member b of which a points to.
a can also be a pointer like object (like a vector<bool>'s stub) override the operators.
(if you don't know what a pointer is, you have another question)
Access operator applicable to (a) all pointer types, (b) all types which explicitely overload this operator
Introducer for the return type of a local lambda expression:
std::vector<MyType> seq;
// fill with instances...
std::sort(seq.begin(), seq.end(),
[] (const MyType& a, const MyType& b) -> bool {
return a.Content < b.Content;
});
introducing a trailing return type of a function in combination of the re-invented auto:
struct MyType {
// declares a member function returning std::string
auto foo(int) -> std::string;
};
x->y can mean 2 things. If x is a pointer, then it means member y of object pointed to by x.
If x is an object with operator->() overloaded, then it means x.operator->().
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Member_and_pointer_operators
a -> b is member b of object pointed to by a
The -> operator, which is applied exclusively to pointers, is needed to obtain the specified field or method of the object referenced by the pointer. (this applies also to structs just for their fields)
If you have a variable ptr declared as a pointer you can think of it as (*ptr).field.
A side node that I add just to make pedantic people happy: AS ALMOST EVERY OPERATOR you can define a different semantic of the operator by overloading it for your classes.
member b of object pointed to by a
a->b