0

In C++, you can double up the indirection operator:

vector<unique_ptr<string>> arr{make_unique<string>("Test")};
cout << **arr.begin() << endl;

But you can't double up the dereference operator:

cout << arr.begin()->->c_str() << endl;

Instead, you have to settle with this (IMO) less-legible alternative:

cout << (*arr.begin())->c_str() << endl;

operator-> is a unary operator that returns a pointer type, so it seems natural to be able to chain them. Is there any good reason for this limitation? Is there some parsing difficulty I'm not seeing?

Edit

In 5.2.5/3, The C++ standard specifies:

If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2

I just wish it was specified as:

If E1 has the type “pointer to class X,” then the expression E1-> is converted to the equivalent form (*(E1)).

It actually seems contrary for this definition to include E1 and E2, since an overloaded operator-> isn't a binary operator.

Rick Yorgason
  • 1,616
  • 14
  • 22
  • 4
    `<<` is not same as 2*`<`... – anishsane May 07 '14 at 11:22
  • 4
    That would be some utterly confusing syntax – Engineer2021 May 07 '14 at 11:23
  • You can't "double up" `*`. You can apply it once, and then apply it a second time to the result of that. The same is true of `->`, you can do `it->first->foo` for example. A `->->` would be a wholly new operator for even less benefit than `->` already has. –  May 07 '14 at 11:25
  • @anishsane Indeed but syntactically that is stupid. 2 of any of the same letters is bad. Someone should give the reasoning of "a->b" is short hand for "(*a).b" so ->-> makes no sense – Alec Teal May 07 '14 at 11:25
  • OP here is a helpful article: http://boredzo.org/pointers/ – Engineer2021 May 07 '14 at 11:35
  • possible duplicate of [C++ pointer dereference operator ( (\*) vs -> )](http://stackoverflow.com/questions/4263796/c-pointer-dereference-operator-vs) – Engineer2021 May 07 '14 at 11:45
  • @staticx I know how to use pointers. The question is why -> wasn't designed to be chainable. – Rick Yorgason May 07 '14 at 11:50
  • @RickYorgason: It's still a duplicate. – Engineer2021 May 07 '14 at 11:51
  • @staticx I'm not asking about the difference between * and ->. – Rick Yorgason May 07 '14 at 11:54
  • This also closely matches your question: https://stackoverflow.com/questions/4923270/is-operator-chained-for-pointers – Engineer2021 May 07 '14 at 11:54
  • @RickYorgason: Did you see the accepted answer to the duplicate? "The -> operator is more convenient when you're following a chain of pointers, because . has higher precedence than *, thus requiring a lot of ungrokkable parentheses." – Engineer2021 May 07 '14 at 11:56
  • @staticx Yes, I saw the accepted answer. I think you're still under the mistaken impression that I'm asking how the -> operator works. There's a huge difference between asking "Is the Pope Catholic?" and "Why is the Pope Catholic?" – Rick Yorgason May 07 '14 at 12:09
  • @RickYorgason: The accepted answer answers your question. The reason being that it would "require a lot of ungrokkable parentheses." – Engineer2021 May 07 '14 at 12:11
  • @staticx The feature I'm asking for *removes* ungrokkable parentheses. – Rick Yorgason May 07 '14 at 12:14
  • @RickYorgason: I don't think so. You would still need them to differentiate between what you are dereferencing. – Engineer2021 May 07 '14 at 12:15
  • @staticx Can you give an example where it would require disambiguation? – Rick Yorgason May 07 '14 at 12:20

3 Answers3

2

Here is a not too technical explanation.

-> is shorthand for the * and the . in (*someptr).memberfunc(). Therefore this can be expressed as someptr->memberfunc().

Two -> would be, in your example, the same as (*(*arr.begin()).).c_str(). Notice the extra dot. This doesn't make sense and it doesn't compile, since . is a binary operator, and * is a unary operator. Therefore, you would have an "extra" dot. You really want two *'s and only one .. Use one -> and one * as you have done.

-> means "dereference and get a member." You want to dereference twice, and get a member once, so double -> is not what you want.

M. K. Hunter
  • 1,778
  • 3
  • 21
  • 27
  • 1
    I assume you meant `(*(*arr.begin()).).c_str())`. You were missing the parenths on begin() and had an extra * after c_str. Assuming that's what you meant to type, it seems entirely reasonable to me for ->-> to be shorthand for that. – Rick Yorgason May 07 '14 at 11:41
  • Thanks. I added the missing parentheses and removed the spurious *. – M. K. Hunter May 07 '14 at 11:43
  • And added a final paragraph. – M. K. Hunter May 07 '14 at 11:46
  • As long as a class does not overload those operators, then they are functionally equivalent – Engineer2021 May 07 '14 at 11:49
  • But does it really mean "dereference and get a member"? When you define your own `operator->` in a class, it's a unary operator. It doesn't know about any members. It just returns a pointer. – Rick Yorgason May 07 '14 at 14:08
  • This [page](http://www.cplusplus.com/doc/tutorial/operators/) describes both `.` and `->` as "member access". The difference being that `.` is used for an object and `->` is used to dereference a pointer then do the member access. I see this also defines it as a unary oparator, so I will reconsider my wording around the fact that relevant information comes before and after `->`. – M. K. Hunter May 07 '14 at 14:50
0

Note that:

(*a).b
a->b

are the same thing

so

a->->b
(*a)->b
(*(*a)).b

So would be okay as an operator, but that isn't in the spirit of -> the spirit is to access things that are pointed to in structures. I'd rather type a->b than (*a).b

So while no technical reason (*a)->b tells you "a is a pointer to a pointer of a structure with b" and a->b->c is totally different to a->->b even though they look similar.

Alec Teal
  • 5,770
  • 3
  • 23
  • 50
  • a->->b would be (*(*a).).b see my answer below. – M. K. Hunter May 07 '14 at 11:36
  • @DutchOven we could define the case of more than one as above and it would work. Also you're looking at `operator->` – Alec Teal May 07 '14 at 11:43
  • 1
    C+ Standard 5.2.5/3: "If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;" – Engineer2021 May 07 '14 at 11:44
  • @AlecTeal, we could define that, in which case it would be a whole new operator (like how `++` is different from `+`.) We could alternatively define `-->` as "dereference twice, get member once", which is the capability desired. But as I said below, and @staticx confirms, an arrow represents a `*` and a `.` (dot), and does not match the desired behavior. – M. K. Hunter May 07 '14 at 11:52
  • Or we could define it as "If E1 has the type "pointer to class X," then the expression E1-> is converted to the equivalent form (*(E1))." and it would work as I described. – Rick Yorgason May 07 '14 at 11:53
  • As long as it forms a group @RickYorgason I am happy (mathematical concept of an operator) – Alec Teal May 07 '14 at 11:59
0

If I understand this correctly, You can get the behaviour that you are looking for with a better design.

The dereference operator actually doesn't really works just as an operator that retrieves a values for you from a pointer, if offers a slightly more complex behaviour.

The business logic of the -> operator is clearly illustrated here, it is also being expanded here, here and you can find a birds eye view about pointer related operators here .

As you can easily guess, If you have T->t you can use the drill down behaviour at your advantage, assuming that you have properly designed and defined T and its own -> operator.

This is a solution that can easily bring some polymorphic behaviour to your application.

Community
  • 1
  • 1
user2485710
  • 9,451
  • 13
  • 58
  • 102
  • I'm not sure overloading `operator->` to automatically drill down is really "better design". In fact, even the author of that answer claims such a design "makes kittens cry". It also doesn't offer a solution when you're using libraries you haven't written yourself. vector> really isn't all that uncommon these days. – Rick Yorgason May 07 '14 at 12:26
  • 1
    @RickYorgason a "better design" was a statement relative to this example, in my opinion pointers in C++ should always be the last resource. in C++ there are other concepts such as iterators and streams that are much better suited for an higher level language, plus with the latest C++11 features you really don't have any good excuse left to use pointers in C++. So yes, it "makes kittens cry" mostly because pointers do not offer a real high level semantic or any high level concept, they can be hard to debug or show some subtle bugs, like any low level concept mixed with an high level language. – user2485710 May 07 '14 at 12:32
  • Do you really think a vector of unique_ptr is a bad design? How else would you store a list of polymorphic objects? Iterators and smart pointers would benefit from this just as much as raw pointers. – Rick Yorgason May 07 '14 at 12:35