Подтвердить что ты не робот

Доступ к оператору [] из указателя

Если я определяю указатель на объект, который определяет оператор [], есть ли прямой способ доступа к этому оператору из указателя?

Например, в следующем коде я могу напрямую обращаться к Vec функциям-членам (например, empty()) с помощью указателя ->, но если я хочу получить доступ к оператору [], мне нужно сначала получить ссылку на объект, а затем вызвать оператор.

#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;
}

Возможно, я ошибаюсь, но похоже, что (*VecPtr).empty() менее эффективен, чем VecPtr->empty(). Вот почему я искал альтернативу (*VecPtr)[].

4b9b3361

Ответ 1

Вы можете выполнить любое из следующих действий:

#include <vector>

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

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

Кстати, в частном случае std::vector вы также можете выбрать: p->at(0), хотя он имеет немного другое значение.

Ответ 2

return VecPtr->operator[](0);

... сделает трюк. Но действительно, форма (*VecPtr)[0] выглядит лучше, не так ли?

Ответ 3

Вы можете использовать его как VecPrt->operator [] ( 0 ), но я не уверен, что вы найдете его менее неясным.

Ответ 4

(*VecPtr)[0] отлично, но вы можете использовать функцию at, если хотите:

VecPtr->at(0);

Имейте в виду, что это (в отличие от operator[]) будет генерировать исключение std::out_of_range, если индекс не находится в диапазоне.

Ответ 5

Другим способом, вы можете использовать ссылку на объект:

#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;
}

Таким образом, r совпадает с v, и вы можете заменить все вхождения (*p) на r.

Предостережение. Это будет работать, только если вы не измените указатель (т.е. измените, на какой объект он указывает).

Рассмотрим следующее:

#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; неверен, потому что вы не можете изменять ссылки: Это изменит вектор, на который ссылается r (v) вместо ссылки на другой вектор (u). Так, опять же, это работает только в том случае, если указатель не изменится при использовании ссылки.

В примерах нужен С++ 11 только из-за vector<int> ... = {...};

Ответ 6

Стоит отметить, что в С++ 11 std::vector есть функция-функция-член, которая возвращает указатель на базовый массив (как const, так и неконстантные версии), позволяя вам написать следующее:

VecPtr->data()[0];

Это может быть альтернативой

VecPtr->at(0);

который несет небольшие накладные расходы во время выполнения, но что более важно, это означает, что вы не проверяете индекс на достоверность перед его вызовом, что не соответствует вашему конкретному примеру.

Подробнее см. std::vector:: данные.

Ответ 7

Люди советуют вам использовать ->at(0) из-за проверки диапазона. Но вот мой совет (с другой точки зрения):

НИКОГДА использовать ->at(0)! Это действительно медленнее. Вы пожертвовали бы успехом только потому, что достаточно ленивы, чтобы не проверять диапазон самостоятельно? Если это так, вы не должны программировать на С++.

Я думаю, что (*VecPtr)[0] в порядке.