openlang

Предупреждение про висячий указатель пропало, а указатель остался

Передаю имя в библиотеку на C++ через обёртку, и сначала написал всё в одну строку, CString::new(name).unwrap().as_ptr(), и rustc сразу предупредил, что временный CString умрёт в конце выражения и указатель будет висячим. Ладно, справедливо. Я вынес это в маленькую функцию, которая создаёт CString в локальной переменной и возвращает as_ptr(), и предупреждение пропало, и я почти успокоился, а потом сообразил, что ничего не изменилось, просто строка теперь умирает в конце функции, а не выражения.

use std::ffi::{c_char, CString};

fn name_ptr(s: &str) -> *const c_char {
    let c = CString::new(s).unwrap();
    c.as_ptr()
}

Это компилируется без единого предупреждения. Линт ловит временное значение в одном выражении, а связанную переменную, которая уходит из функции, не ловит, хотя в справке к самому предупреждению написано, что для возвращаемого указателя связывания внутри функции мало. А если сторона C++ ещё и сохраняет указатель у себя, а не только читает его во время вызова, то даже переменной в вызывающем коде не хватит, и я пока не знаю, что именно она делает, документации там почти нет. Решил пока держать CString в структуре-обёртке рядом с дескриптором, чтобы они жили одинаково, и посмотреть, что скажут.

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Посчитайте владельцев, и станет проще. Хранение в структуре даёт одного владельца с тем же временем жизни, что и у дескриптора, и это правильно, если библиотека читает указатель только пока дескриптор жив. Неправильно, если библиотека держит указатель после закрытия дескриптора или освобождает его сама.

    Если держит, передавайте владение явно. CString::into_raw отказывается от владения на стороне Rust, и ровно один CString::from_raw на том же указателе возвращает его, когда библиотека закончила. Один вызов туда, один обратно, и указатель никогда не должен попасть в free из C, потому что память выделил аллокатор Rust. Если библиотека никак не сообщает, когда она закончила, это и надо выяснить до выбора.

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

  1. getline оставляет буфер вызывающему, даже когда возвращает -1

    POSIX getline выделяет или увеличивает буфер через переданный указатель, и этот буфер принадлежит вызывающему с первого же вы…

    Ответы 4c
  2. Ссылка на интерфейс и ссылка на объект для одного экземпляра

    Ошибка времени жизни, которую я чаще всего встречаю в старом коде на Delphi, возникает, когда на одном экземпляре смешивают д…

    Ответы 5object-pascal
  3. Один и тот же вызов с sink, сначала копия, потом перенос

    Nim 2 решает, копировать или переносить, в каждой точке вызова. Не на уровне proc. Тот же аргумент, та же proc. Первый вызов…

    Ответы 2nim