Why do compilers not accept '.' and '->' both for pointer and instances?

Why do compilers not accept '.' and '->' at the same time. I now a pointer requires '->' and an instance a '.', but why not let us use both?

Obviously for a good reason, but I cannot think of one myself.
Please show how you are going to use them both?
They don't do the same thing. '.' is used to access a member of the object. When '->' is used on a raw pointer it is used to access a member of the object that the pointer is pointing to. '->' can also be defined for class types.

Here is an example where you can use both '.' and '->' but with different meanings.
1
2
3
4
5
6
7
8
9
10
11
12
struct A
{
	void reset();
};

std::unique_ptr<A> m(new A);

// Calls A::reset.
m->reset();

// Calls std::unique_ptr<int>::reset.
m.reset();
Last edited on
Maybe you mean something as

instance.pointer->object;

This statement is correct.
Last edited on
> why not let us use both?

If you create a user-defined type of your own, and for some reason you want to use both '.' and '->' to access its members, you can.


> Please show how you are going to use them both?

Showing how to use them both is embarrassingly trivial:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

struct not_a_pointer
{
    int v = 10 ;
    int foo( int a ) 
    { std::cout << "not_a_pointer::foo(" << a << ")\n" ; return v += a ; }

    not_a_pointer* operator->() { return this ; }
    const not_a_pointer* operator->() const { return this ; }
};

int main()
{
    not_a_pointer nptr ;

    nptr.foo( nptr->foo(40) ) ;

    std::cout << nptr.v << ' '
              << nptr->v << '\n' ;
}

http://liveworkspace.org/code/3IgLFR$0
Apparently there is some historical reason as to why there is both . and -> for member access - (at least that is what I read some time previously).

I myself could not understand why - ( because the compiler knows whether something is an object or a pointer and should be able to act accordingly
and so only one of them (lets say for argument sake the dot operaror) would
be needed).

I'll do a search and see if I can find that write up again.
I suppose there is no other reason for operator-> to exist other than make pointer's member access easier. It is easier (for me) to write

pointer->member

instead of writing

(*pointer).member

It is also faster to type -> compared to the latter example. This way you can be a little more productive.
Last edited on
The point is that the two operators do different things.

. simply accesses a member of an object

-> de-references the pointer and then accesses a member of the object being pointed to.

Having two separate operators removes ambiguity - it tells the compiler exactly what to do, and it tells anyone reading the code what the compiler is doing.

This is important, because it's possible to create classes which have pointer-like behaviour. These classes can use the standard syntax of pointers, by overloading the * and -> operators.

The classic example is a smart pointer object, as implemented in the Boost libraries and now incorporated into the C++11 standard. These are objects, and therefore have members, so it is necessary to use the . operator to access those members. However, they also behave like pointers, so they override the -> operator to make it possible to access members of the data they are pointing to.

Imagine if the object being pointed to by the smart pointer had a member with the same name as a member of the smart pointer object itself. How would the compiler know which one you meant, without the distinction between . and -> operators?
Last edited on
Helixirr wrote:
I suppose there is no other reason for operator-> to exist other than make pointer's member access easier. It is easier (for me) to write

pointer->member

instead of writing

(*pointer).member

It is also faster to type -> compared to the latter example. This way you can be a little more productive.

+1.

Explaining to the op:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

struct S {
    int I;
};

int main()
{
    S test;
    S * pointerTest = &test;
    /*
    At this point:

    test.I is equal to pointerTest->I

    But you can see how test is S, and pointerTest is S*.
    They are NOT the same thing, NOT the same type.
    
    Also, as noted above,

    pointerTest->I is equal to (*pointerTest)->I
    */
}
As far as I know, a compiler knows if it's an object or pointer to an object. And thus the compiler should be able to generate the correct code. I'm searching for an explanation why the C standard defined it this way.

The thing about smart pointer objects and overriding the -> operator makes me believe the distinction is necessary. I never used this but I'll look into this more.



1
2
3
4
5
6
7
8
9
class S {
    int I;
};

void foo(S* bar)
{
    bar->I = 10;
    bar.I = 10;  //In this case, the compiler could know what bar is and could generate the correct code
}
I find this a useless compiler functionality.
I prefer to know by myself what type something is.

That functionality also will call a lot of newbies asking why is this possible and why is not the inverse possible.

See overriding of -> operator.

It's like inserting a new system.
( http://www.cplusplus.com/forum/articles/11153/ )
Topic archived. No new replies allowed.