Безопасно ли предполагать, что хранилище векторов STL всегда является непрерывным?
Вопрос
Если у вас есть вектор STL, размер которого был изменен, безопасно ли брать адрес элемента 0 и предполагать, что остальная часть вектора будет сохранена в памяти?
например ,
vector<char> vc(100);
// do some stuff with vc
vc.resize(200);
char* p = &vc[0];
// do stuff with *p
Решение
Да, это обоснованное предположение (*).
Из стандарта C ++ 03 (23.2.4.1):
Элементы вектора хранятся последовательно, что означает, что если v является вектором, где T - некоторый тип, отличный от bool, то он подчиняется тождество &v[n] == &v[0] + n для всех 0 <= n < v.размер().
(*) ...но следите за тем, чтобы массив не был перераспределен (делая недействительными любые указатели и итераторы) после добавления в него элементов.
Другие советы
Стандарт C ++ 03 добавил формулировку, разъясняющую, что векторные элементы должны быть смежными.
C ++03 23.2.4 Параграф 1 содержит следующий язык, который является не в стандартном документе C ++ 98:
Элементы a
vector
хранятся последовательно, что означает, что еслиv
являетсяvector<T, Allocator>
гдеT
является каким-то типом, отличным отbool
, тогда это подчиняется тождеству&v[n] == &v[0] + n
для всех0 <= n < v.size()
.
Херб Саттер рассказывает об этом изменении в одной из своих записей в блоге, Не съеживайся:Векторы гарантированно будут смежными:
...смежность фактически является частью векторной абстракции.Это настолько важно, фактически, что когда было обнаружено что стандарт C ++ 98 не полностью гарантирует непрерывность, в Стандарт C ++ 03 были внесены поправки, чтобы явно добавить гарантию.
Хранилище всегда является непрерывным, но оно может перемещаться по мере изменения емкости вектора.
Если у вас был указатель, ссылка или итератор на нулевой элемент (или любой другой элемент) перед операцией изменения емкости, он недействителен и должен быть переназначен.
std::vector
гарантирует, что элементы хранятся в непрерывном массиве, и поэтому является предпочтительной заменой массивов, а также может использоваться для взаимодействия с зависящим от платформы низкоуровневым кодом (например, вызовами Win32 API).Чтобы получить указатель на массив, используйте:
&myVector.front();
ДА.
она всегда должна быть смежной