Почему деструктор не вызывается для Box :: from_raw ()? - PullRequest
0 голосов
/ 28 февраля 2019

Я передаю необработанный указатель на два разных замыкания и преобразую необработанный указатель в ссылку, используя Box::from_raw(), и программа работает нормально.

Однако после преобразования необработанногоуказатель на ссылку, деструктор должен вызываться автоматически, как сказано в документации:

Эта функция небезопасна, поскольку неправильное использование может привести к проблемам с памятью.Например, двойное освобождение может произойти, если функция вызывается дважды для одного и того же необработанного указателя.

Однако я могу получить доступ к ссылке на ABC даже после вызова Box::from_raw() для необработанного указателядважды, и все работает нормально.

struct ABC {}

impl ABC {
    pub fn new() -> ABC {
        ABC {}
    }

    pub fn print(&self, x: u32) {
        println!("Inside handle {}", x);
    }
}

fn main() {
    let obj = ABC::new();
    let const_obj: *const ABC = &obj;

    let handle = |x| {
        let abc = unsafe { Box::from_raw(const_obj as *mut ABC) };
        abc.print(x);
    };
    handle(1);

    let handle1 = |x| {
        let abc = unsafe { Box::from_raw(const_obj as *mut ABC) };
        abc.print(x);
    };
    handle1(2);
}

Rust Playground

Почему деструктор не вызывается для ABC после handle и до handle1 какфункция description для Box::from_raw() определяет:

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

Почему Box::from_raw() работает несколько раз на необработанном указателе?

1 Ответ

0 голосов
/ 28 февраля 2019

TL; DR вы делаете это неправильно.


преобразование необработанного указателя в ссылку

Нет, вы преобразовываете его в Box, не ссылка.

программа работает нормально

Это не так.Вам просто «повезло», что небезопасная память и неопределенное поведение не вызывают сбой.Вероятно, это связано с тем, что ваш тип не имеет фактических данных.

для ссылки, деструктор должен вызываться автоматически

Нет, когда ссылки выходятобласти видимости, деструктор не выполняется.

Почему деструктор не называется

Это равно , что является одной из нескольких причин, по которым вашкод полностью и полностью сломан и небезопасен.

Добавьте код, который будет запускаться при уничтожении:

impl Drop for ABC {
    fn drop(&mut self) {
        println!("drop")
    }
}

И вы увидите, что он вызывается 3 раза:

Inside handle 1
drop
Inside handle 2
drop
drop

Я могу получить доступ к ссылке на ABC

Да, что небезопасно.Вы нарушаете правила, которые должны соблюдать при написании кода unsafe.Вы взяли необработанный указатель, сделали что-то, чтобы сделать его недействительным, и затем обращаетесь к исходной, теперь недопустимой переменной.

В документации также говорится:

единственный действительный указатель для передачи этой функции - тот, который взят из другого Box через функцию Box::into_raw.

Вы также игнорируете этот аспект.

...