Итератор по сравнению со ссылкой по сравнению с [закрытым] указателем

7
задан pmr 1 March 2010 в 19:37
поделиться

4 ответа

Если итератор признан недействительным, он также сделает недействительным указатель / ссылку, в которые итератор был преобразован. Если у вас есть это:

std::vector<T>::iterator it = ...;
T *p = &(*it);
T &r = *p;

, если итератор недействителен (например, вызов push_back может сделать недействительными все существующие векторные итераторы), указатель и ссылка также будут признаны недействительными.

Из стандарта 23.2.4.2/5 (емкость вектора):

Примечания: Перераспределение делает недействительными все ссылки, указатели и итераторы, относящиеся к элементам в последовательности.

Такой же общий принцип справедлив и для std :: list. Если итератор признан недействительным, указатели и ссылки, в которые преобразуется итератор, также становятся недействительными.

Разница между std :: list и std :: vector - это то, что вызывает недействительность итератора. Итератор std :: list действителен до тех пор, пока вы не удалите элемент, на который он ссылается. Если std :: vector <> :: push_back может сделать итератор недействительным, то std :: list <> :: push_back не может.

6
ответ дан 7 December 2019 в 07:44
поделиться

Мне нравится параметр указателя. Это вопрос стиля. Я предпочитаю этот стиль типа параметра:

  • Постоянная ссылка: Большой объект передается для чтения. Ссылка позволяет избежать расточительного копирования. Выглядит как передача по значению в точке вызова.
  • Указатель: объект передается для чтения и записи . У вызова будет знак «&» для получения указателя, поэтому запись становится очевидной во время проверки кода.
  • Неконстантная ссылка: запрещена, потому что проверка кода не может определить, какие параметры могут быть изменены в качестве побочного эффекта.

Как вы говорите, итератор создает бессмысленную зависимость от родительского типа контейнера. (std :: list реализован как двусвязный список, поэтому только удаление его записи делает вектор недействительным. Так что это будет работать.)

0
ответ дан 7 December 2019 в 07:44
поделиться

В текущей версии C++ (т.е. без конструкторов перемещения). т.е. без конструкторов перемещения) указатели на элементы, встроенные в список std::list, будут аннулированы вместе с итераторами списка.

Однако если вы используете std::list*>, то vector* может перемещаться, а vector - нет, поэтому ваш указатель на вектор останется действительным.

С добавлением конструкторов перемещения в C++0x содержимое вектора, вероятно, останется на месте, если только размер самого вектора не будет изменен, но любое такое предположение будет по своей сути не переносимым.

0
ответ дан 7 December 2019 в 07:44
поделиться

Если содержимое родительского вектора повторно распределяется после порождения ваших рабочих потоков, то их указатели, ссылки, итераторы или что-либо еще почти наверняка недействительны. Список МОЖЕТ быть другим (учитывая, как они распределяются), но я не знаю, и это может даже зависеть от платформы.

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

Если список, который вы используете, гарантированно не перераспределяет свое "другое" пространство при добавлении (или удалении) членов, то это позволит достичь того, что вы ищете, но вектор определенно небезопасен. Но в любом случае, способ доступа к нему (указатель, ссылка или итератор) вероятно не имеет большого значения, пока ваш "корневой контейнер" не собирается перемещать его содержимое.

Редактировать:

Как упоминалось в комментариях ниже, вот блок о списке с сайта SGI (выделение мое) :

Списки обладают важным свойством, что вставка и сращивание не не аннулируют итераторы к элементам списка, и что даже удаление аннулирует только итераторы, которые указывают на элементы, которые удаляются. порядок итераторов может быть изменен (то есть, list::iterator может иметь другого предшественника или преемника после операции со списком, чем до этого), но сами итераторы не будут аннулированы или сделаны так, чтобы указывать на разные элементы, если только это аннулирование или мутация явно.

Таким образом, это в основном говорит: "Используйте список в качестве основного хранилища", а затем каждый рабочий может сбрасывать данные в свой собственный и знает, что они не будут аннулированы, когда другой рабочий полностью закончит работу и его вектор будет удален из списка.

1
ответ дан 7 December 2019 в 07:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: