2013-02-23 7 views
-4

Итак, я увидел this question, в котором в основном говорится, что ссылки и итераторы недействительны вместе.Почему ссылки никогда недействительны?

Я понимаю, почему итераторы признаны недействительными в некоторых случаях, но Почему ссылки недействительны?

С практической точки зрения, я не понимаю, почему это требуется.

Было ли это просто дизайнерским решением или есть какая-то практическая причина?

EDIT: Чтобы уточнить, насколько я понимаю основную структуру, это просто указатели на данные, которые необходимо будет перераспределена (данные (и, таким образом, ссылка на него) может оставаться без изменений). Правильно?

Некоторый тест-код:

#include <vector> 
#include <iostream> 
using namespace std; 

int main() 
{ 
    vector<string> yourVect; 
    yourVect.push_back("def"); 
    vector<string>::iterator iter = yourVect.begin(); 
    const string& ref = *iter; 
    yourVect.insert(yourVect.begin(), "abc"); 
    cout << ref << endl; // !! --- doesn't work - why ?? --- !! 
    cout << *iter << endl; // obviously doesn't work 
} 
+0

вектор может быть перераспределен – sashoalm

+0

Как вы думаете, ваша ссылка является ссылкой на то, когда базовое динамическое распределение, которое оно было инициализировано, было уничтожено из-под нее? – WhozCraig

+1

Я не понимаю, как вы можете перемещать объекты в новое место после перераспределения и все еще ожидать, что старые все еще будут там ?! – Mehrdad

ответ

2

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

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

Гарантии относятся к «наихудшему случаю», поэтому не гарантируется, что после операции insert ссылки будут по-прежнему действительны. Или, если говорить по-другому, вставка в вектор может аннулировать итераторы и ссылки.

Кроме того, я не понимаю, почему вы считаете, что существует существенная разница в этом поведении между ссылками и итераторами - итератор vector обычно является указателем на ссылочную позицию vector (часто скрытую внутри класса, определенного для реализации) так что это более или менее то же самое, что и ссылка.


  1. IIRC в C++ 11 на самом деле они "перемещены" (как в std::move); это не меняет того факта, что старые ссылки будут указывать на освобожденную память.
+0

@ Dukeling: см. Править для ответа (в частности, второй абзац). –

+0

@ Dukeling: да, это на самом деле одна из точек 'vector' (одна большая часть последовательной памяти вместо отдельного блока памяти для каждого объекта). Если вместо этого вы хотите вектор указателей, вам просто нужно попросить его (создайте 'vector '); Кстати, в Boost есть удобные классы для управления временем жизни объектов, хранящихся в «векторе» указателей. –

+2

@ Dukeling Это стандартизованный стандарт. в частности, в C++ 11 § 23.3.6.1p1 * «Элементы вектора сохраняются смежно, что означает, что если v - вектор , где T - некоторый тип, отличный от bool, то он подчиняется идентификатору & v [ n] == & v [0] + n для всех 0 <= n WhozCraig

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