Задать вопрос
@Sasha_88

Как проверить перемещается ли в памяти объект при «перемещении»?

Я хочу написать простой пример для проверки перемещения объекта в памяти. Тут имеется ввиду, что я хочу узнать меняется ли адрес объекта, когда он передается от одного владельца к другому. По идее адрес меняться не должен, так как это перемещение существует только в исходном коде для ссылочных типов. Ссылочных в обычном смысле, для которых память выделена в куче и переменная ссылается на объект. Как раз что делает Box. Я ожидаю, что данные после перемещения должны лежать по тому же адресу фактически. Потому, что если Rust будет еще и данные в куче копировать, то это лишняя трата времени и это тогда совсем оптимизацией не является.

Но я не могу написать пример без вызова clone(), чтобы он скомпилировался.
#![allow(unused)]
fn main() {

  let b = Box::new(4);
  
  check_b(&b);
  let c = b;      // Здесь происходит move
  
  check_c(&c);
}

fn check_c(val: &Box<i32>){
    println!("address c: {}\n", Box::into_raw(val.clone()) as usize);
}

fn check_b(val: &Box<i32>){
   println!("address b: {}\n", Box::into_raw(val.clone()) as usize);
}

А с вызовом clone() получается, что я не могу это проверить. Данные копируются:

address b: 104808743070512

address c: 104808743070544

Подскажите как переписать пример, чтобы можно было это проверить?
Спасибо
  • Вопрос задан
  • 84 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 3
bingo347
@bingo347
Crazy on performance...
При перемещении адрес на стеке изменится, а адрес памяти выделенной на куче - нет.
Тут очень тонкий момент, который нужно понимать, данные которые мы помещаем в Box или Vec будут размещены на куче, но сами Box и Vec - это такие же структуры, как и любые другие, просто на них есть некоторая логика для управления памятью на куче, в случае 64 битной архитектуры и T: Sized, Box<T> будет занимать 8 байт на стеке и размер T на куче, а Vec<T> - 24 байта на стеке (указатель на начало, длина и фактически выделенная память) и размер T умноженный на capacity на куче.

fn main() {
    let a = Box::new(42);
    println!("Stack address of a: {:p}", &a);
    println!("Heap address of a: {:p}", &*a);
    
    let b = a;
    println!("Stack address of b: {:p}", &b);
    println!("Heap address of b: {:p}", &*b);
}
Stack address of a: 0x7fff59586010
Heap address of a: 0x58cf76717b10
Stack address of b: 0x7fff59586018
Heap address of b: 0x58cf76717b10
Ответ написан
Комментировать
@Sasha_88 Автор вопроса
Я изменил пример и получилось, что походу адрес не меняется. То есть при перемещении владения объект лежит там же в памяти:
#![allow(unused)]
fn main() {

  let b = Box::new(4);
  
  check_b(&b);
  let c = b;          // Здесь происходит move
  
  check_c(&c);
}

fn check_c(val: &Box<i32>){
    println!("address c: {}\n", &raw const val as usize);
}

fn check_b(val: &Box<i32>){
   println!("address b: {}\n", &raw const val as usize);
}

address b: 140733161839864

address c: 140733161839864
Ответ написан
Комментировать
fenrir1121
@fenrir1121
Начни с документации
Как проверить перемещается ли в памяти объект при «перемещении»?

В общем случае: посмотреть реализован ли Copy, поскольку у него семантика перемещения заменяется на семантику копирования. За исключением Copy все копирования и аллокации в расте явные, вроде методов clone() или to_vec().

В случае с Box вы уже сами пришли к ответу, достаточно было просмотреть на адрес в указателе.

Ну и код проверки какой-то странный, достаточно этого
fn main() {
    let b = Box::new(4);
    check(&b);
    let c = b;
    check(&c);
}

fn check(val: &i32) {
    println!("address: {:p}", val);
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы