Почему в документации Rust говорится, что совместное использование ссылки на вектор создаст недопустимый вектор, даже если вектор находится в куче?
Ниже приводится выдержка из главы " Язык программирования Rust" о владении:
Теперь рассмотрим следующий фрагмент кода:
let v = vec![1, 2, 3]; let mut v2 = v;
Первая строка выделяет память для векторного объекта
v
в стеке, как это делается дляx
выше. Но в дополнение к этому он также выделяет некоторую память в куче для фактических данных ([1, 2, 3]
). Rust копирует адрес этого выделения кучи во внутренний указатель, который является частью векторного объекта, помещенного в стек (назовем его указателем данных).Стоит отметить (даже рискуя указать очевидное), что векторный объект и его данные находятся в отдельных областях памяти, а не в виде единого непрерывного выделения памяти (по причинам, которые мы не будем рассматривать в данный момент), Эти две части вектора (одна в стеке и одна в куче) должны всегда согласовываться друг с другом в отношении таких вещей, как длина, емкость и т. Д.
Когда мы двигаемся
v
вv2
, Rust на самом деле делает побитовую копию векторного объектаv
в выделении стека, представленногоv2
, Эта мелкая копия не создает копию размещения кучи, содержащую фактические данные. Это означает, что будет два указателя на содержимое вектора, указывающих на одно и то же распределение памяти в куче. Это нарушит гарантии безопасности Rust, введя гонку данных, если можно будет получить доступ к обоимv
а такжеv2
в то же время.Например, если мы обрезали вектор до двух элементов через
v2
:v2.truncate(2);
а также
v
были все еще доступны, мы в конечном итоге с недействительным вектором, так какv
не знал бы, что данные кучи были усечены. Теперь часть вектораv
в стеке не согласен с соответствующей частью в куче.v
все еще думает, что в векторе есть три элемента, и с радостью предоставит нам доступ к несуществующему элементуv[2]
но, как вы уже знаете, это рецепт катастрофы. Тем более, что это может привести к ошибке сегментации или, что еще хуже, позволить неавторизованному пользователю читать из памяти, к которой у него нет доступа.
После усечения вектора с помощью v2
усеченные значения обновляются в памяти кучи. v1
по-прежнему видит кучу памяти и после усечения видит новые значения. Так почему книга говорит
а также
v
были все еще доступны, мы в конечном итоге с недействительным вектором, так какv
не знал бы, что данные кучи были усечены
2 ответа
Я думаю, я понимаю это. Ключ должен знать, что у Rust есть этот внутренний указатель, который снова является пространством в стеке, которое Rust использует для определения адреса данных в куче!
Если v2
изменяет эти данные в куче, v2
внутренний указатель обновляется с новым адресом выделения данных, в то время как v1
Внутренний указатель все равно будет ссылаться на старый адрес выделения данных!
Что вы упускаете, так это то, что Vec
содержит как указатель на кучу, так и len
или длина данных кучи. Если v2
усекает Vec
возможно, что усеченные данные были освобождены, и v1
до сих пор считает, что усеченная память все еще является частью вектора.