Почему в документации 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 до сих пор считает, что усеченная память все еще является частью вектора.

Другие вопросы по тегам