Accessing the [] operator from a pointer
Asked Answered
S

7

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)[].

Slake answered 13/12, 2011 at 17:55 Comment(5)
Why do you want to avoid (*VecPtr)[0] ?Hl
@Rob Edited with a reason. My assumption might be wrong, but it's why I asked.Slake
(*VecPtr).empty() and VecPtr->empty() are exactly the same thing (unless VecPtr is something that overloads operator* and operator-> with conflicting meaning.Merritt
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).Hl
@KerrekSB because some people don't know how to get at the operator[] from a pointer at all.Kleeman
D
56

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.

Decolonize answered 13/12, 2011 at 17:58 Comment(3)
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?Henceforward
@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.Hostel
@ancientchild agreed, the last one should not be used as normal practice.Henceforward
T
12
return VecPtr->operator[](0);

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

Tongs answered 13/12, 2011 at 17:58 Comment(0)
C
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.

Cicatrix answered 13/12, 2011 at 18:3 Comment(0)
C
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> ... = {...};

Chinch answered 20/9, 2017 at 17:50 Comment(4)
r = u; is fine and it will do assignment between the two vectors ; this has nothing to do with pCoact
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.Chinch
r = u; will have the same effect whether or not you later modify the pointerCoact
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.Chinch
K
3

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

K answered 13/12, 2011 at 17:58 Comment(0)
M
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.

Mainspring answered 3/11, 2015 at 14:13 Comment(0)
G
-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.

Gassman answered 16/7, 2016 at 12:12 Comment(1)
why at(0) is slow?Accrual

© 2022 - 2024 — McMap. All rights reserved.