LINUX.ORG.RU

Все ли типы в расте обязаны быть Bitwise-Moveable?

 ,


1

4

Знакомлюсь с растом, пока даже не столько чтоб на нём писать, а чтоб понять подходы и там где это возможно и осмысленно применять в С++.

С трейтами Copy, и Clone и Drop всё вроде понятно. Не понял пока одного - верно ли что при передачи владения переменной с перемещеним (например со стека в вектор - так же вроlе можно?) всегда выполняется просто побитовое перемещение в другое место?

Иными словами - может ли unsafe тип внутри содержать указтель на себя, который в специальном трейте типа Drop можно будет корректировать при таком перемещении, или так нельзя?

Usecase следующий - сделать аналог Vec, который при малом количестве элементов будет хранить их не в куче, а в себе, и соотвественно указывать будет не на кучу, а на внутренний буфер в самой переменной.

★★

Ответ на: комментарий от vlad9486

Сделанный вариант SmallVec как раз таки НЕ хранит указать на себя, а на каждое обращение к DeRef добавляет один условный переход self.spilled() - чтоб понять откуда читать из внутреннего массива или из кучи.


    #[inline]
    fn triple(&self) -> (*const A::Item, usize, usize) {
        unsafe {
            if self.spilled() {
                let (ptr, len) = self.data.heap();
                (ptr, len, self.capacity)
            } else {
                (self.data.inline().ptr(), self.capacity, A::size())
            }
        }
    }

impl<A: Array> ops::Deref for SmallVec<A> {
    type Target = [A::Item];
    #[inline]
    fn deref(&self) -> &[A::Item] {
        unsafe {
            let (ptr, len, _) = self.triple();
            slice::from_raw_parts(ptr, len)
        }
    }
}

Вряд ли это особо дорого, и ясно что вообще можно вызвать один раз и чтение работать с полученнмы slice, но для низкоуровнего примитива низкоуровнего языка - выглядит как минимум подозрительно.

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

Так что вопрос о требовании побитовой перемещаемости типов - остаётся актуальным.

GPFault ★★
() автор топика
Ответ на: комментарий от GPFault

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

vlad9486
()
Ответ на: комментарий от anonymous

то есть можно наконец пойти и посмотреть в документации Rust 4 (fixed) случая, для которых нужен unsafe, чтобы всякий раз не ломался шаблон.
да, то для чего нужен unsafe, без него сделать нельзя, а если можно, это или баг компилятора, или ССЗБ

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от vlad9486

то что нужен unsafe для таких хаков - не проблема - даже хорошо, хаки должны быть отмечены так.

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

В общем, нагуглил пока только запрет на перемещение: https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md

GPFault ★★
() автор топика
Последнее исправление: GPFault (всего исправлений: 1)
Ответ на: комментарий от GPFault

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

WatchCat ★★★★★
()
Ответ на: комментарий от WatchCat

Сишной либы нету. Хочу сделать unsafe-тип, который будет хранить указатель. Этот указатель иногда на себя, а иногда на кучу. Как правильно удалять - решит в drop сравнив адрес указателя со своим, на то он и unsafe. Это классическая оптимизация для хранения коротких векторов строк и т.п.

Но возникает проблема из-за того что объект в любое время могут переместить и он об этом никак не узнает - в этом случае указатель на себя станет указателем на мусор. Насколько я понял из ссылок в это теме - на текущий момент версии раста - «does not change the fact that a Rust compiler considers all types movable». Так что «уведомлять на каждое перемещение» не получится и создать неперемещаемый тип на стеке тоже не получится (есть Pin<T> но он для кучи).

GPFault ★★
() автор топика
Ответ на: комментарий от GPFault

Я думаю что если его «переместят», то адрес поменяется только если его переместят в другой тред - он попадет в другой стек. А иначе, перемещение будет чисто логическим (воображаемым) и останется он в том же месте того же стека. Но гарантировать я, конечно же, ничего не могу. Вот если его скопируют, тогда адрес поменяется. Но это можно обработать в коде метода Clone::clone.

vlad9486
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.