Вектор оборачивает свой массив таким образом, что он притворяется, что элементы массива являются членами самого вектора. Вот почему вы не можете изменить элементы массива константного вектора. Вектор также позволяет получить доступ к адресу его элементов массива. Но если я получу указатель на элемент массива вектора (который является элементом самого вектора), а затем назначу вектор, мой указатель больше не будет определяться для указания на элемент вектора. Это имеет смысл для push_back()
или что-то в этом роде, чтобы аннулировать указатели, потому что никто не сказал, что push_back()
не делал ничего смешного с элементами вектора.
У любого обычного типа мои указатели на его элементы остаются действительными после присваивания. Итак, не то чтобы обходных путей не было, но разве это не сделало бы вектор нерегулярным типом?
То же самое касается std::string
и многие другие типы списков / хранилищ в стандарте.
отредактировано: имел ввиду обычный тип, когда я сказал конкретный тип.
изменить, еще один момент: так, в c, если вы получили указатель на член структуры, присвоение этой структуры буквально не может изменить местоположение объекта, потому что вы не могли притворяться, что элемент массива был часть структуры. Однако в векторе это правило нарушено. Член является членом объекта, потому что он буквально связан с одним и тем же именем объекта и всегда будет таким, пока объект не будет уничтожен. Поэтому никакая обычная операция не должна иметь возможности изменить что-то подобное.
Понятие регулярного типа в C ++ происходит из «Элементов программирования» Степанова. Это в основном список разумных / полезных представлений о типе. Например, он должен поддерживать равенство, а присваивание и присваивание должны иметь условие post, при котором переменная присваивания сравнивается равной с исходной переменной (конечно, это копирование, а не перемещение).
Однако регулярность не включает в себя понятие, которое вы описываете. Бетон — это совершенно другая вещь, это просто любой класс, который может быть создан, т.е. не имеет чисто виртуальных методов.
У Степанова есть классификация, связанная с тем, что вы описываете. У меня нет под рукой моей копии, но я думаю, что он ссылается на нее как на внутреннюю, так и на внешнюю: вопрос в том, действительно ли биты, составляющие экземпляр типа, включают всю информацию этого значения. Вектор является внешним, поскольку три указателя, которые обычно составляют сам вектор, не полностью его описывают, в куче также есть материал, который является частью представления вектора, даже если он не содержится «внутри» фактического экземпляра вектора.
Проблема, которую вы описываете, возникает из-за того, что vector является внешним. Каждый раз, когда вы берете указатели, которые идут непосредственно к внешним частям типа, а затем выполняете операции с этим типом, эти указатели могут быть признаны недействительными. Структура с простыми членами, такими как int, однако, является внутренней, вся информация содержится внутри самой структуры. Это вызывает разницу в поведении.
Если вам нужен динамически изменяемый тип массива, вам, в основном, нужно использовать кучу, а использование кучи означает, что ваш тип будет внешним, и в этот момент вы откроете себя для этих проблем. Вот почему все стандартные контейнеры имеют подробные описания того, когда их итераторы могут быть признаны недействительными.
Других решений пока нет …