Комментарии 20
Есть там ещё к чему придраться, есть. Нет стабильных целочисленных параметров дженериков, из-за чего массивы не являются первоклассными типами. Нет стабильного синтаксиса для создания макросов и для боксинга. Нет стабильного placement new.
Нет простых экстеншенов, а существующий обходной путь не дружит с возвращаемым impl Trait
, и нет стабильного способа их подружить.
Нет стабильного placement new.
А зачем вам в Rust с его дешёвым перемещением placement new?
Лично мне — просто для порядка. Лишнее перемещение всё равно явно лишнее, даже если дешёвое.
У placement new в C++ прикол вроде больше с тем что можно избавится от выделения динамической памяти, насколько я это понимаю.
Так это и в Rust можно, placement new для этого не требуется
Sorry за медленный вопрос, а можете продемонстрировать как это сделать?
trait Trait {}
struct Hello {
something: Box<dyn Trait>
}
Как можно положить в Hello.something что-то что реализует Trait, но без динамической памяти?
В таком виде — никак, ведь Box подразумевает динамическую память. В плюсах, знаете ли, тоже placement new для unique_ptr не работает!
А вот так динамическая память уже не обязательна:
struct Hello {
something: &dyn Trait
}
Спасибо за ответ! Я имел в виду могу ли я заменить чем-то Box чтобы хранить объект в рамках Hello. В плюсах я могу вместо unique_ptr сделать:
struct ITrait {};
struct Hello {
uint8_t something[MAX_SIZE];
}
И размещать в этом буфере объекты с помощью placement new и использовать с помощью `(ITrait*)(something)->doSomething'. Если объект Hello размещен на стеке, то объект производного класса тоже будет на стеке и динамический полиморфизм будет работать.
В вашем варианте не хватает лайфтаймов и подразумевается что Hello
не владеет объектом (в отличие от Box). Весь мой опыт с rust что не хватает многих таких мелочей которые можно сделать оптимальнее в C++, но приходится делать немного менее оптимальнее (за счет рантайма).
Кстати, так, как вы написали, работать, вообще говоря, не будет: 1) нужно обеспечить выравнивание указателя, 2) даже если с выравниванием всё хорошо, нельзя использовать указатель, сконверченный из uint8_t, это UB; надо использовать указатель, который вернул placement new.
Ага, а если объект вышел за пределы MAX_SIZE — получите и распишитесь повреждение памяти. Если плюсы такое позволяют — это ещё не значит что так и правда можно делать.
В этом сценарии placement new нужно понимать некоторое количество деталей и это не rocket since. Как много где в C++ надо проверять возможные переполнения и тут это можно делать в compile time (так что программа не соберется если вы пытаетесь сделать placement new для объекта который размером больше MaxSize). В реальности это будет не uint8_t something[MAX_SIZE];
а что-то вроде InplaceStorage<ITrait, MAX_SIZE> storage_;
где эти вопросы решены один раз.
В rust наверное все это тоже можно как-то сделать с MaybeUninit
и Pin
, возможно не так часто нужно.
В rust наверное все это тоже можно как-то сделать с MaybeUninit и Pin
Хотелось бы увидеть. Я вот не знаю как это сделать.
+1. Я вот не понимаю этот момент, раст говорит что async/await у него это zero cost, однако это явно не zero cost поскольку там сразу несколько костов, в том числе на выделение памяти. В корутинах у C++ есть сценарии когда выделение памяти может быть убрано компилятором и кроме того там можно своим "new" управлять выделением памяти для корутин.
Нет стабильного placement new.
Нестабильного тоже уже нет, выпилили
Ещё я вспомнил костыль под названием FnBox
.
И лично я бы ещё с большим удовольствием увидел условные заимствования. Чтобы например можно было делать так:
fn fill_buf_and_ignore_interrupts(reader: &mut impl BufRead) -> io::Result<&[u8]> {
loop {
match reader.fill_buf() {
Ok(buf) => return Ok(buf),
Err(e) => {
if e.kind() != io::ErrorKind::Interrupted {
return Err(e);
}
}
}
}
}
Сейчас borrow checker такое осилить не в состоянии.
Ну и оптимизация хвостовой рекурсии не помешала бы, так как замена цикла рекурсией в некоторых случаях позволяет лучше объяснить borrow checker'у что к чему.
Миграция на инфраструктуру async-await в Rust