2009-09-07 5 views
6

При использовании контейнеров STL STL, при каких условиях необходимо обращаться к ссылочным значениям? Например, любые ссылки недействительны после следующего вызова функции в контейнер?Устойчивые ссылки в контейнерах STL

{ 
std::vector<int> vector; 
vector.push_back (1); 
vector.push_back (2); 
vector.push_back (3); 

vector[0] = 10;  //modifies 0'th element 

int& ref = vector[0]; 
ref = 10;    //modifies 0'th element 

vector.push_back (4); 
ref = 20;    //modifies 0'th element??? 

vector.clear(); 
ref = 30;    //clearly obsurd 
} 

Я понимаю, что в большинстве реализаций stl это сработает, но меня интересует то, что требует стандартная декларация.

--edit: Im заинтересованы потому что я хотел бы попробовать STXXL (http://stxxl.sourceforge.net/) библиотеки для C++, но я понял, что ссылки, возвращаемые контейнеры не были постоянными в течение нескольких операций чтения, и, следовательно, не совместимы без внесения изменений (хотя и поверхностно) к моему существующему stl-коду. Пример:

{ 
std::vector<int> vector; 
vector.push_back (1); 
vector.push_back (2); 


int& refA = vector[0]; 
int& refB = vector[1]; //refA is not gaurenteed to be valid anymore 
} 

Я просто хотел бы знать, если это означало, что STXXL контейнеры, не 100% совместимость, или в самом деле, если бы я использовал STL контейнеров в небезопасном/реализации зависимого пути все время.

+2

Я нашел соответствующий ответ на их FAQ http://algo2.iti.uni-karlsruhe.de/dementiev/stxxl/trunk/FAQ.html «Вы не должны передавать или хранить ссылки на элементы во внешней структуре данных памяти . Когда используется эта ссылка, блок, содержащий этот элемент, может быть больше не во внутренней памяти. ", Поэтому ответ НЕТ, ссылки на элементы контейнера не имеют такого же поведения, что и их STL-копии. – Akusete

+1

Просматривая стандарт C++, все контейнеры имеют typedefs 'reference',' const_reference', 'pointer' и' const_pointer', которые настроены на соответствующие typedefs из базового распределителя. Кажется, что комитет по стандартам первоначально хотел создать абстракцию для ссылок и указателей, чтобы даже эти вещи могли «управляться» контейнером (в том виде, в котором итераторы уже есть), используя прокси-серверы, но, тем не менее, Стандартные мандаты, что тип 'allocator :: pointer' будет' T * 'и т. д., что делает сами typedefs в конечном счете бессмысленными. –

+0

У меня такое же чувство, читая интерфейсы большинства контейнеров STL, но я не мог найти дискуссию о том, почему они только отправились на полпути. – Akusete

ответ

12

О вставки в векторах, стандарт говорит в 23.2.4.3/1:

[insert()] приводит к перераспределению, если новый размер больше, чем старый мощности. Если перераспределение не происходит, все итераторы и ссылки перед тем, как точка ввода останется действительна.

(Хотя это на самом деле это говорит о insert(), таблица 68 показывает, что a.push_back(x) должно быть эквивалентно a.insert(a.end(), x) для любого вектора a и значением x.) Это означает, что если вы заранее сохранили память reserve(), то (и только тогда) итераторы и ссылки гарантированно не будут аннулированы, если вы insert() или push_back() других предметов.

Что касается удаления предметов, 23.2.4.3/3 говорит:

[erase()] аннулирует все итераторы и ссылки после точки стирания.

Согласно таблице 68 и таблице 67 соответственно, pop_back() и clear() эквивалентны соответствующим вызовам erase().

+0

чертовски, я думаю, что невозможно реализовать 100% совместимые с STL реализации контейнеров с поддержкой дисков. – Akusete

+1

Я думаю, нет, если вы хотите, чтобы ссылки были свободно сделаны и удерживались. Но, на мой взгляд, сохранение долгосрочных ссылок на элементы, которые живут в другой структуре данных, является «неудобной» практикой - есть ли причина, по которой вы не можете просто сохранить итераторы? –

+0

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

1

Я ожидаю, что ссылки будут признаны недействительными только какой-либо явной или неявной resize() (см также max_size, capacity и reserve методы).

+0

Согласен. Почему clear() недействителен для памяти? Он просто установил бы его нулевым или похожим. – jkeys

+0

@Hooked: Невозможно полагаться на это поведение. Стандартная реализация библиотеки C++ позволяет делать все, что захочет, при условии соблюдения семантических правил, изложенных в стандарте ISO C 2003 года. –

1

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

7

Некоторые основные правила для вектора:

  • Перераспределение недействительными все референции, указатели и итераторы для элементов вектора.
  • Вставки may недействительные ссылки, указатели и итераторы.
  • Вставка или удаление элементов отменяет ссылки, указатели и итераторы, которые ссылаются на следующие элементы: .
  • Если вставка вызывает перераспределение, аннулирует все ссылки, итераторы и указатели.
+1

* Если вы зарезервировали достаточно места, то при вставке гарантировано, что перераспределение не произойдет (возможно, очевидно, но важно). –

Смежные вопросы