Зачем Box <[T]> нужно 16 байт в памяти, а ссылочному срезу нужно только 8? (на машине x64) - PullRequest
14 голосов
/ 23 апреля 2019

Рассмотрим:

fn main() {
    // Prints 8, 8, 16
    println!(
        "{}, {}, {}",
        std::mem::size_of::<Box<i8>>(),
        std::mem::size_of::<Box<&[i8]>>(),
        std::mem::size_of::<Box<[i8]>>(),
    );
}

Почему собственные фрагменты занимают 16 байтов, а ссылочные фрагменты занимают только 8?

Ответы [ 2 ]

17 голосов
/ 23 апреля 2019

Box<T> в основном *const T (На самом деле это новый тип около Unique<T>, который сам по себе является NonNull<T> с PhantomData<T> (для dropck ), но давайте придерживаться *const Tдля простоты).

Указатель в Rust обычно имеет тот же размер, что и size_of::<usize>(), за исключением случаев, когда T представляет собой тип динамического размера (DST).В настоящее время размер Box<DST> равен 2 * size_of::<usize>() (точное представление не стабильно на момент написания статьи).Указатель на DST называется FatPtr.

. В настоящее время существует два вида DST: срезы и черты.FatPtr для среза определяется следующим образом:

#[repr(C)]
struct FatPtr<T> {
    data: *const T,
    len: usize,
}

Примечание: Для указателя признака len заменяется указателем на vtable.

Получив эту информацию, на ваш вопрос можно ответить:

  • Box<i8>: i8 - это тип размера => в основном такой же, как *const i8 => 8 байт (с шириной указателя 64 бита)
  • Box<[i8]>: [i8] - это DST => в основном то же самое, что FatPtr<i8> => размер 16 байтов (с шириной указателя 64 бита)
  • Box<&[i8]>: &[i8] - , а не DST.Это в основном то же самое, что *const FatPtr<i8> => 8 байт (с шириной указателя 64 бита)
3 голосов
/ 23 апреля 2019

Размер ссылки зависит от "размера" ссылочного типа:

  • Ссылка на тип размера - это одиночный указатель на адрес памяти.
  • Ссылка на тип без размера - это указатель на память и размер указанной точки отсчета.Это то, что называется жирный указатель :

    #[repr(C)]
    struct FatPtr<T> {
        data: *const T,
        len: usize,
    }
    

A Box - это особый тип указателя, который указывает на кучу, но он все ещеуказатель.

Зная это, вы понимаете, что:

  • Box<i8> равен 8 байтам, поскольку размер i8,
  • Box<&[i8]> равен 8 байтам, посколькуразмер ссылки,
  • Box<[i8]> равен 16 байтам, потому что срез не имеет размера.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...