C ++ STL Вектори: Отримати ітератор з індексу?


200

Отже, я написав купу коду, який звертається до елементів у stl-векторі за індексом [], але тепер мені потрібно скопіювати лише фрагмент вектора. Схоже, vector.insert(pos, first, last)це функція, яку я хочу ... за винятком того, що я є лише першою та останньою як ints. Чи є приємний спосіб отримати ітератор цих значень?


1
Дивіться також: stackoverflow.com/q/2152986/365102
Mateen Ulhaq

Якщо я не помиляюся, жодна з відповідей не перевіряє меж, що може бути проблемою. Зокрема, документи std :: advance говорять, що поведінка не визначена, якщо ви використовуєте її для проходження меж базових контейнерів.
Мартін Печка

Відповіді:


293

Спробуйте це:

vector<Type>::iterator nth = v.begin() + index;

4
Як правило, ви можете використовувати ту саму арифметику з ітераторами STL, ніж з покажчиками. Вони призначені для обміну при використанні алгоритмів STL.
Вінсент Роберт

18
@VincentRobert: Інакше. Покажчики є дійсними реалізаціями випадкових ітераторів STL, найпотужнішої категорії. Але інші, менш потужні категорії, такі як ітератори вперед, не підтримують однакову арифметику.
MSalters

6
Я хотів би, щоб я додав свої п’ять центів до цієї відповіді та рекомендуюstd::next(v.begin(), index)
стрику

87

спосіб, згаданий @dirkgently ( v.begin() + index )приємний і швидкий для векторів

але std::advance( v.begin(), index ) найбільш загальний спосіб і для ітераторів випадкового доступу також працює постійний час.

EDIT
відмінності у використанні:

std::vector<>::iterator it = ( v.begin() + index );

або

std::vector<>::iterator it = v.begin();
std::advance( it, index );

додано після приміток @litb.


не std ::перед вимагає ітератора non-const як першого аргументу?
золотоПсевдо

ви можете використовувати std :: advance з const та non-const ітераторами
bayda

1
ви не повинні довіряти msvc з цього приводу. він має нестандартне розширення, що змушує його приймати подібні речі, проте всі інші компілятори поводяться стандартно і відмовляються від цього.
Йоханнес Шауб - ліб

1
Я думаю, що проблема полягає в плутанині щодо значення "const" :перед () буде радісно працювати над const_iterator <T>, який є мутаційним ітератором, що посилається на елемент const типу T; він не буде працювати над об'єктом ітератора, який є самим const (тобто "const iterator <T>" або "iterator <T> const").
j_random_hacker

7
Якщо ви знаєте, що маєте справу з компанією std::vector, використовувати це не має сенсу std::advance. Це лише заманює вас думати, що ви пишете контейнерно-агностичний код (чого ви цього не робите, придумуючи правила недійсності ітератора, різні складності виконання та інше). Єдиний випадок, коли std::advanceє сенс, коли ви пишете шаблон самостійно, який не знає, з яким ітератором він має справу.
Фріріх Раабе

47

Також; auto it = std::next(v.begin(), index);

Оновлення: потрібен компілятор, сумісний з C ++ 11x


2
Слід зазначити, що це спосіб C ++ 11! std :: next еквівалентно std ::перед. Використання цих функцій, а не використання арифметики, значно полегшує заміну типів контейнерів. Навіть працює на c-масивах afaik, як і std :: begin та std :: end.
Zoomulator

2
Слід також зазначити, що std :: advance розроблений ідіот, оскільки він використовує посилання як вихід, а не повернене значення.
Віктор Шер

1
for (auto it = початок (c); it! = end (c); advance (it, n)) {...}
Zoomulator

2
Обидва мають своє використання. stda :: аванс корисний для зміни ітератора на місці. Це питання продуктивності в циклі. Я б вважав за краще наступне у випадку доручення, як ви пропонуєте. Я просто виявив це трохи різко, стверджуючи, що це ідіот. Обидві функції були розроблені з урахуванням різних ситуацій, хоча вони в основному однакові.
Zoomulator

5
@Zoomulator: Якщо копіювання вашого ітератора викликає ефективність, у вас є більші проблеми.
Mooing Duck


-3

Актуально std :: вектор повинні використовуватися як вкладка C, коли це необхідно. (C ++ стандартні запити про те, що для реалізації вектора, наскільки я знаю - заміна масиву у Вікіпедії ) Наприклад, цілком легально робити це наступне, на мою думку:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Звичайно, або foo не повинен копіювати адресу, передану як параметр, і зберігати її кудись, або ви повинні забезпечити у своїй програмі ніколи не натискати жодного нового елемента в vec, або просити змінити його ємність. Або ризик помилки сегментації ...

Тому у вашому прикладі це призводить до

vector.insert(pos, &vec[first_index], &vec[last_index]);

Мене здивує, чому вони вирішили відмовитися від ітераторів, якщо вони просто вказівники ... вони по суті "приховують" ці можливості.
mpen

За постійність? Так як це дозволить вам легко видалити векторний екземпляр для будь-якого іншого типу контейнера у вашому коді.
Ів Баумес

4
& vec [i] дає вказівник, який не обов'язково сумісний з вектором <> :: ітератором. vec.begin () + я все ще має перевагу бути будь-яким ітератором, який ваша бібліотека визначає, включаючи, наприклад, перевірені ітератори в режимі налагодження. Отже, якщо вам не потрібен покажчик (наприклад, для вводу / виводу), завжди слід віддавати перевагу ітераторам.
sellibitze

@KerrekSB З 23.3.6.1 у стандартному проекті c ++: "Елементи вектора зберігаються безперервно, це означає, що якщо v - вектор <T, Аллокатор>, де T - якийсь тип, відмінний від bool, то він підкоряється ідентичності & v [ n] == & v [0] + n для всіх 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: це не має нічого спільного з векторними ітераторами. Однак правда, що голі вказівники також є ітераторами - вони просто не векторні ітератори.
Керрек СБ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.