#c #vector #refactoring
#c #указатели #операторы
Вопрос:
Если я определяю указатель на объект, который определяет []
оператор, есть ли прямой способ получить доступ к этому оператору из указателя?
Например, в следующем коде я могу напрямую обращаться Vec
к функциям-членам (таким как empty()
), используя оператор указателя ->
, но если я хочу получить доступ к []
оператору, мне нужно сначала получить ссылку на объект, а затем вызвать оператор.
#include <vector>
int main(int argc, char *argv[])
{
std::vector<int> Vec(1,1);
std::vector<int>* VecPtr = amp;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)[]
.
Комментарии:
1. Почему вы хотите избежать
(*VecPtr)[0]
?2. @Rob Отредактирован с указанием причины. Мое предположение может быть неверным, но именно поэтому я спросил.
3.
(*VecPtr).empty()
иVecPtr->empty()
являются одним и тем же (если только VecPtr не является чем-то, что перегружаетoperator*
иoperator->
имеет противоречивое значение.4. Если
VecPtr
является типом указателя, то(*VecPtr).XXX
, по определению, эквивалентноVecPtr->XXX
. Потери эффективности нет. IfVecPtr
— это тип без указателя, который реализуетoperator*
иoperator[]
, тогда вам нужно будет изучить их, чтобы увидеть, какой из них более эффективен (вероятно, они одинаковы).5. Как этот вопрос получает одобрение?? Он основан на одной из самых плохо информированных и недостаточно изученных предпосылок и вряд ли представляет ценность для других.
Ответ №1:
Вы можете выполнить любое из следующих действий:
#include <vector>
int main () {
std::vector<int> v(1,1);
std::vector<int>* p = amp;v;
p->operator[](0);
(*p)[0];
p[0][0];
}
Кстати, в конкретном случае std::vector
, вы также можете выбрать: p->at(0)
, хотя это имеет немного другое значение.
Комментарии:
1. Последний интересный, не могли бы вы объяснить, что там происходит под капотом? Это первый [0], ссылающийся на «первый элемент», на который указывает указатель? Аналогично тому, как векторная ссылка является указателем на начало массива?
2. @ThekoLekena точно, для указателей на полные типы T оператор [] определен для доступа к i-му элементу массива (путем вычисления sizeof(T) * i). Конечно, поскольку в этом случае у нас есть указатель на один вектор, наличие чего-либо еще, кроме [0], было бы неопределенным поведением. редактировать : я бы не стал выбирать последний, поскольку я нахожу его менее идиоматичным.
3. @ancientchild согласился, последний не следует использовать в качестве обычной практики.
Ответ №2:
return VecPtr->operator[](0);
…сделает свое дело. Но на самом деле (*VecPtr)[0]
форма выглядит лучше, не так ли?
Ответ №3:
(*VecPtr)[0]
все в порядке, но вы можете использовать at
функцию, если хотите:
VecPtr->at(0);
Имейте в виду, что это (в отличие operator[]
от) вызовет std::out_of_range
исключение, если индекс не находится в диапазоне.
Ответ №4:
Есть другой способ, вы можете использовать ссылку на объект:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = amp;v;
// Reference to the vector
vector<int> amp;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 = amp;v;
// Reference to the vector
vector<int> amp;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 = amp;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
) .
Итак, опять же, это работает только в том случае, если указатель не изменится при использовании ссылки.
Примеры нуждаются в C 11 только из-за vector<int> ... = {...};
Комментарии:
1.
r = u;
это нормально, и он будет выполнять присваивание между двумя векторами; это не имеет ничего общего сp
2. И это то, что я подразумеваю под «неправильным». Цитирую себя: «вы можете заменить все вхождения
(*p)
наr
«, но «Это будет работать, только если вы не будете изменять указатель», потому что нет способа изменитьr
, как вы изменили бы значение*p
.r = u;
«изменит вектор, на который ссылается,r
вместо ссылки на другой вектор» — это не будет иметь желаемого эффекта.3.
r = u;
будет иметь тот же эффект, независимо от того, измените вы позже указатель или нет4. Да, но я не понимаю, почему вы это говорите. Опять же, под «неправильным» я подразумеваю, что он не делает то, что
p = ...
мог бы сделать. И я говорю о замене всех*p
случаев на byr
. Но если в вашем коде у вас естьp = ...
, заменаp = ...
наr = ...
является неправильной.
Ответ №5:
Вы можете использовать его как VecPrt->operator [] ( 0 )
, но я не уверен, что он покажется вам менее непонятным.
Ответ №6:
Стоит отметить, что в C 11 std::vector имеет функцию-член ‘data’, которая возвращает указатель на базовый массив (как const, так и неконстантные версии), что позволяет вам написать следующее:
VecPtr->data()[0];
Это может быть альтернативой
VecPtr->at(0);
что влечет за собой небольшие накладные расходы во время выполнения, но, что более важно, его использование подразумевает, что вы не проверяете индекс на достоверность перед его вызовом, что неверно в вашем конкретном примере.
Для получения более подробной информации см. std::vector::data .
Ответ №7:
Люди советуют вам использовать ->at(0)
из-за проверки диапазона. Но вот мой совет (с другой точки зрения):
НИКОГДА не используйте ->at(0)
! Это действительно медленнее. Вы бы пожертвовали производительностью только потому, что вы достаточно ленивы, чтобы не проверять диапазон самостоятельно? Если это так, вам не следует программировать на C .
Я думаю (*VecPtr)[0]
, все в порядке.
Комментарии:
1. почему at(0) работает медленно?