46

If I define a pointer to an object that defines the [] operator, is there a direct way to access this operator from a pointer?

For example, in the following code I can directly access Vec's member functions (such as empty()) by using the pointer's -> operator, but if I want to access the [] operator I need to first get a reference to the object and then call the operator.

#include <vector>

int main(int argc, char *argv[])
{
    std::vector<int> Vec(1,1);
    std::vector<int>* VecPtr = &Vec;

if(!VecPtr->empty())      // this is fine
    return (*VecPtr)[0]; // is there some sort of ->[] operator I could use?

return 0;
}

I might very well be wrong, but it looks like doing (*VecPtr).empty() is less efficient than doing VecPtr->empty(). Which is why I was looking for an alternative to (*VecPtr)[].

Malabarba
  • 4,473
  • 2
  • 30
  • 49
  • 5
    **Why** do you want to avoid `(*VecPtr)[0]` ? – Robᵩ Dec 13 '11 at 17:59
  • @Rob Edited with a reason. My assumption might be wrong, but it's why I asked. – Malabarba Dec 13 '11 at 18:01
  • 4
    `(*VecPtr).empty()` and `VecPtr->empty()` are exactly the same thing (unless VecPtr is something that overloads `operator*` and `operator->` with conflicting meaning. – UncleBens Dec 13 '11 at 18:03
  • 2
    If `VecPtr` is a pointer type, then `(*VecPtr).XXX` is, by definition, equivalent to `VecPtr->XXX`. There is no loss of efficiency. If `VecPtr` is a non-pointer type that implements `operator*` and `operator[]`, then you'll have to examine them to see which is more efficient (they are probably the same). – Robᵩ Dec 13 '11 at 18:06
  • 3
    How is this question getting upvoted?? It is based on one of the most ill-informed and under-researched premises and hardly of value to others. – Kerrek SB Dec 13 '11 at 18:24

7 Answers7

54

You could do any of the following:

#include <vector>

int main () {
  std::vector<int> v(1,1);
  std::vector<int>* p = &v;

  p->operator[](0);
  (*p)[0];
  p[0][0];
}

By the way, in the particular case of std::vector, you might also choose: p->at(0), even though it has a slightly different meaning.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 2
    That last one there is interesting, could you explain what is happening there under the hood? Is that first [0] referring to the "first element" pointed to by the pointer? Similar to how a vector reference is a pointer to the beginning to an array? – Theko Lekena Feb 05 '18 at 17:41
  • 3
    @ThekoLekena exactly, for pointers to complete-types T, the [] operator is defined to access the ith element of the array (by calculating sizeof(T) * i). Of course, since in this case we have a pointer to **one** vector, having anything else than [0] would be undefined behaviour. **edit**: i wouldn't choose the last one though, as i find it less idiomatic. – LeonTheProfessional Jun 25 '20 at 09:32
  • @ancientchild agreed, the last one should not be used as normal practice. – Theko Lekena Jun 26 '20 at 13:25
12
return VecPtr->operator[](0);

...will do the trick. But really, the (*VecPtr)[0] form looks nicer, doesn't it?

Sean
  • 29,130
  • 4
  • 80
  • 105
4

There's another way, you can use a reference to the object:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> v = {7};
    vector<int> *p = &v;

    // Reference to the vector
    vector<int> &r = *p;
    cout << (*p)[0] << '\n'; // Prints 7
    cout <<    r[0] << '\n'; // Prints 7

    return 0;
}

This way, r is the same as v and you can substitute all occurrences of (*p) by r.

Caveat: This will only work if you won't modify the pointer (i.e. change which object it points to).

Consider the following:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> v = {7};
    vector<int> *p = &v;

    // Reference to the vector
    vector<int> &r = *p;
    cout << (*p)[0] << '\n'; // Prints 7
    cout <<    r[0] << '\n'; // Prints 7

    // Caveat: When you change p, r is still the old *p (i.e. v)
    vector<int> u = {3};
    p = &u; // Doesn't change who r references
    //r = u; // Wrong, see below why
    cout << (*p)[0] << '\n'; // Prints 3
    cout <<    r[0] << '\n'; // Prints 7

    return 0;
}

r = u; is wrong because you can't change references: This will modify the vector referenced by r (v) instead of referencing another vector (u). So, again, this only works if the pointer won't change while still using the reference.

The examples need C++11 only because of vector<int> ... = {...};

KinGamer
  • 491
  • 5
  • 7
  • `r = u;` is fine and it will do assignment between the two vectors ; this has nothing to do with `p` – M.M Sep 17 '18 at 07:18
  • And this is what I mean by "wrong". Quoting myself, "you can substitute all occurrences of `(*p)` by `r`", but "This will only work if you won't modify the pointer", because there's no way to change `r` as you would change the value of `*p`. `r = u;` "will modify the vector referenced by `r` instead of referencing another vector" -- it won't have the intended effect. – KinGamer Sep 18 '18 at 02:55
  • `r = u;` will have the same effect whether or not you later modify the pointer – M.M Sep 18 '18 at 03:00
  • Yes, but I don't get why you're saying that. Again, by "wrong" I mean it doesn't do what `p = ...` would do. And I'm talking about substituting all ocurrences of `*p` by `r`. But if in your code you have `p = ...`, replacing `p = ...` by `r = ...` is wrong. – KinGamer Sep 18 '18 at 15:49
4

(*VecPtr)[0] is perfectly OK, but you can use the at function if you want:

VecPtr->at(0);

Keep in mind that this (unlike operator[]) will throw an std::out_of_range exception if the index is not in range.

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
3

You can use it as VecPrt->operator [] ( 0 ), but I'm not sure you'll find it less obscure.

lapk
  • 3,838
  • 1
  • 23
  • 28
1

It is worth noting that in C++11 std::vector has a member function 'data' that returns a pointer to the underlying array (both const and non-const versions), allowing you to write the following:

VecPtr->data()[0];

This might be an alternative to

VecPtr->at(0);

which incurs a small runtime overhead, but more importantly it's use implies you aren't checking the index for validity before calling it, which is not true in your particular example.

See std::vector::data for more details.

Jan Holecek
  • 2,131
  • 1
  • 16
  • 26
-3

People are advising you to use ->at(0) because of range checking. But here is my advise (with other point of view):

NEVER use ->at(0)! It is really slower. Would you sacrifice performance just because you are lazy enough to not check range by yourself? If so, you should not be programming in C++.

I think (*VecPtr)[0] is ok.

user3785008
  • 85
  • 1
  • 8