LINUX.ORG.RU

Rust и создание больших массивов

 ,


3

6

Вот этот очень простой код потенциально легко вызовет stack overflow (если нет, то надо просто увеличить 16777216), хотя не должен (мы ведь на самом деле выделяем место в куче в итоге).

#[derive(Copy, Clone)]
pub struct Item {
    a: i32,
    b: i32
}

pub struct Items {
    items: [Item; 16777216]
}

impl Items {
    pub fn new() -> Items {
        Items {
            items: [Item { a: 0, b: 1 }; 16777216]
        }
    }
}

fn foo() -> Box<Items> {
    Box::new(Items::new())
}

Пруф: https://rust.godbolt.org/z/8sWsoKojx

Для Ъ: Массив сначала создаётся на стеке, а только потом выделяется память и происходит memcpy в кучу. Максимальные оптимизации не спасут.

К тому же не забываем про оверхед копирования. Я готов поверить разработчикам Rust, что копирование при создании структур из нескольких сотен байт не создаст заметной просадки, но я верю, что пример выше будет статистически значимо работать медленнее уже на нескольких тысячах элементов, а не обязательно 16 миллионов.

Как принято создавать в Rust такие массивы? unsafe или есть решения получше?

Мне нравится Rust последнее время, сколько я к нему присматриваюсь, но вот такая очевидная мелочь как copy elision не предусмотрена для типа системного языка... Или я просто всё делаю не так и Items::new надо писать как-то иначе?

★★★★★

Последнее исправление: KivApple (всего исправлений: 2)

Не пойму сути проблемы. Почему изначально не создавать массив в куче, если он планируется большим? Если у тебя работоспособность приложения зависит от оптимизации, ты что-то делаешь не так.

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

Не пойму сути проблемы.

Как в Rust создать экземпляры больших классов? Которые не помещаются в стеке.

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

Зачем вносить лишний indirection? Так вместо указателя на объект будет указатель на указатель на объект.

Плюс лишняя возможность выстрелить себе в ногу, так как размер вектора не фиксирован и не является частью его типа.

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

В плюсах copy elision начиная с какого-то стандарта гарантирован даже при отключенных оптимизациях и side effects в конструкторе перемещения (он не будет вызван, потому что объект сразу построится в нужном месте).

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

Выдели тогда в куче с помощью vec, потом преврати его в boxed slice, потом в boxed-массив фиксированной длины.

pub struct Items {
    items: Box<[Item; 16777216]>
}

impl Items {
    pub fn new() -> Self {
        let items = vec![Item { a: 0, b: 1}; 16777216];
        Self {
            items: items.into_boxed_slice().try_into().expect("correct size"),
        }
    }
}

Косо, криво, но пока так — до тех пор, пока placement new не завезут.

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

Зачем вносить лишний indirection? Так вместо указателя на объект будет указатель на указатель на объект.

Нет там лишнего разыменования. Vec<T> - это указатель на данные, ёмкость и длина. Ну и до кучи: Box<[T]> - это указатель и длина, Box<[T; N]> - это просто указатель.

Плюс лишняя возможность выстрелить себе в ногу

Это как сказать. Получить панику из-за выхода за границу массива можно с такой-же лёгкостью (или также нелегко, на выбор) как и из-за выхода за границу инициализированной части вектора.

Ну и массив должен быть всегда полностью инициализирован. Если нужно инициализировать его поэлементно, то придётся иметь дело с [MaybeUninit<T>; N] и ансейфом.

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 2)

Выдумываем проблемы по типу, хочу как в С, чтобы потом упиваться попытками растфанбоев тебя переиграть, толстовато, чёт с каждым годом уровень троллей падает. Но, чтобы не было флеймом, так и быть, сделаю вид что клюнул и посоветую писать на С в нём же уже всё как ты хочешь.

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

Зачем ты кормишь ангажированного крестьянина, вектор ему тоже не подойдёт потому что есть ансейф внутри. А значит «аааа, попались, коко, ворованный С, кококо, оно ничем не лучше С а только хуже, кококо, мне очень нравится Раст, но вот видите какой он плохой куткудахтахтах»

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

Нет там лишнего разыменования

Vec - это указатель на данные

Сам себя опровергаешь. Если у тебя есть структура с встроенным массивом фиксированного размера, то доступ к любому элементу осуществляется через addr + offset + i * element_size, где addr это адрес начала структуры, offset это сдвиг, по которому начинается массив. Если у тебя Vec, то тебе нужно сходить по указателю два раза, сначала вытащить указатель по адресу addr + offset, а потом по этому указателю уже вытащить данные по адресу addr1 + i * element_size. Для современных процессоров это нехорошо, т.к. портит конвееры. ТС хочет правильного, просто в Rust это пока не реализовано.

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

unsafe внутри библиотек меня ничуть не напрягает. Меня напрягает двойное разыменовывание (это плохо для производительности, оратор выше объяснил почему) + возможность менять размер после создания у структуры, которая не должна его менять (это просто некрасиво).

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

unsafe или есть решения получше?

Штоштыфраерсдалназад? Уже значит устраиваю решения и не получше? Короче, сбрось овечью шкуру, у тебя есть сисиплюсплюс, там все по красоте, оставь Раст, не нужен он тебе, сирыйубогийихромой

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

Сам себя опровергаешь.

Я говорил про отсуствие разницы в количестве indirection между Vec<T> и Box<[T; N]>. Не так понял что имел в виду KivApple.

Для современных процессоров это нехорошо, т.к. портит конвееры.

Полагаю, что это будет ощутимо только при рандомном доступе к элементам Vec<Vec<T>> по сравнению с [[T; N]; M].

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

Я говорил про отсуствие разницы в количестве indirection между Vec<T> и Box<[T; N]>. Не так понял что имел в виду KivApple.

А если у нас Box<Vec<T>>? (потому что массив встроен в другую структуру с дополнительными полями и мы хотим аллоцировать в куче всю структуру).

KivApple ★★★★★
() автор топика

Мне нравится Rust последнее время, сколько я к нему присматриваюсь, но вот такая очевидная мелочь как copy elision не предусмотрена для типа системного языка…

Тут немного более сложная проблема, на самом деле. Для такой конструкции:

    Box::new(Items::new())

наверное большая часть языков программирования гарантирует, что Items::new() будет вызвана до Box::new(). Обе функции могут иметь побочные эффекты, а значит оптимизатор просто так поменять их местами не может, ведь тогда поменяется наблюдаемое поведение программы.

В случае Items::new() можно считать, что побочных эффектов нет. Но тут я не уверен, потому что там происходит запись новых значений в память. Считается ли запись чего-то в память побочным эффектом, если на эту память ешё никто не ссылается?

Box::new() вообще может запаниковать, если не получится выделить память. И в случае паники нужна гарантия того, что Items::new() либо не будет вызвана вообще, либо не будет давать побочные эффекты.

В C++ для решения этой проблемы существует явный placement new. В расте тоже были какие-то телодвижения в этом направлении, но текущий статус мне неизвестен. Также в расте хотели на уровне MIR сделать оптимизации для таких случаев, так как LLVM их не может оптимизировать (кроме самых тривиальных).

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

А если у нас Box<Vec<T>>?

Если у нас будет Box<Vec<T>>, вместо Box<[T; N]> и Vec<T> будет часто вылетать из L1 кэша и каждый раз мы обрабатываем небольшое число элементов вектора/массива, то массив будет заметно выгоднее.

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

Царь, уходите отсюда и не грубите людям …

Владимир

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

Просто возьми Vec и не засовывай его в Box

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

Проблема надуманная. Вместо Box<struct_with_slice> можно держать struct_with_vec, а в хипе будет лежать сам массив большого размера. Плюсы у такого подхода в том, что, например, запихав подобные структуры в вектор получишь нормальную возможность пробежаться по нему, просматривая поля с метадатой, и всё это будет в кеше. И ресайз этого вектора из структур с вектором внутри не будет вешать всю систему. Фактически польза от внедрения слайсов будет только если они относительно маленькие, но тогда для упирания в проблнему их должно быть много. Это не то что бы реалистичный случай.

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

Не надуманная. Язык в safe не позволяет выполнить без оверхэда тривиальную операцию - new T[size]{}. В очередной раз рассказы про безопасность и zero-cost оказались сказками. Особенно забавно на этом фоне смотрятся рассказы про какой-то кэш и прочую чушь.

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

Типичная глупость от фаната сишечки. Во-первых, а с чего собственно возникла идея, что в безопасном расте должен быть аналог операции new T[size]? Это низкоуровневая конструкция другого языка, которую и в плюсах-то использовать не рекомендуют. В расте результат подобной операции в 90% случаев был бы небезопасным, неинициализированная память же, доступная простым индексатором. Причём аналог конструктора по умолчанию в Расте существует только в виде библиотечного трейта, так что, по идее, поведение голого компилятора зависеть от него не должно.

Аналог на Раст, безопасный выглядит, в зависимости от смысла, так:

let mut v = Vec::with_capacity(N);

или

    let mut v = Vec::new();
    v.resize(N, 0);

Впрочем, это всё оффтопик, вопрос в теме совершенно другой был.

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

Во-первых, а с чего собственно возникла идея, что в безопасном расте должен быть аналог операции new T[size]?

Действительно, с чего возникла идея, что можно выделить массив либо другой объект на куче? Не знаю, наверное, что бы можно было иметь время жизни стореджа, не ограниченное вызывающим скоупом.

К тому же, этот аналог в расте уже есть, только не «zero-cost», да и вообще не работающий с чем-либо размером больше пары байт. Ты даже собственной методичке противоречишь.

Это низкоуровневая конструкция другого языка, которую и в плюсах-то использовать не рекомендуют

Ну показывай, кто и где не рекомендует. Низкоуровневость показывай. Чего каждая жертва пропаганды кидает какие-то лозунги, которые ничего не стоят?

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

Ну это просто роспись в своей несостоятельности. Давай я тебе помогу - там нет никакой неинициализированной памяти. Зачем ты приходишь сюда позориться?

Аналог на Раст, безопасный выглядит, в зависимости от смысла, так:

Vec::with_capacity(N);

Vec::new();

Тебя обманули, это не раст. Вектор на расте ты написать не сможешь, тебе нужен будет C(unsafe). Это именно та проблема, которая означена в ОП. Язык не может выразить работу с неинициализированной памятью, которая будет везде, кроме хэлвордов. И каждый раз нужно будет обмазываться unsafe(сишкой), который тут же ломает все «гарантии» недоязычка.

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

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

Вот именно, что не знаешь. Беги перечитывать rust book.

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

Аноним решил ещё насосать. Ок.

Действительно, с чего возникла идея, что можно выделить массив либо другой объект на куче? Не знаю, наверное, что бы можно было иметь время жизни стореджа, не ограниченное вызывающим скоупом.

В расте для этого есть человеческий мув.

К тому же, этот аналог в расте уже есть, только не «zero-cost», да и вообще не работающий с чем-либо размером больше пары байт.

Ну да, внезапно есть возможность не пользоваться вектором там где не надо. Слайс фиксированного размера может быть добавлен в структуру. Для слайсов, хранящихся на хипе есть вектор.

Ну показывай, кто и где не рекомендует. Низкоуровневость показывай. Чего каждая жертва пропаганды кидает какие-то лозунги, которые ничего не стоят?

Страуструп не рекомендует. new/delete пользоваться не рекомендуется, либо владеющие указатели, либо контейнеры. А ты, клоун, не знал? Тебе RAII дали человеческий, а ты всё по книжке из 87 года программируешь.

Видел выступление, где Страуструп обещал написать книгу страниц на 100 про настоящий современный C++, без всякой сишной и раннеплюсовой порнографии. Не знаю, написал ли.

Ну это просто роспись в своей несостоятельности. Давай я тебе помогу - там нет никакой неинициализированной памяти. Зачем ты приходишь сюда позориться?

И тут анонимус узнаёт, что забитая нулями память != инициализированная. Например попробуй создать массив из Box, например. Или из обычных указателей (null тоже нет). Раст - это не то же что C++, тут немного другие идеи задействованы.

Тебя обманули, это не раст. Вектор на расте ты написать не сможешь, тебе нужен будет C(unsafe).

Царь, ты бы сразу написал что это ты, я бы время не тратил. Раст - это не язык без ансейфа, это язык, в котором ансейф явно выделен и изолирован. Поэтому вот это «ага, попался, ансейф» - это вообще мимо кассы. Этим, кстати, Раст отчасти и лучше плюсов, то что в плюсах ты должен узнавать читая книжки, ну типа что new пользовательском коде не рекомендуется, в Расте выделено синтаксисом.

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

Ладно, раз поддельный царь расстроился, что не смог прочитать моё сообщение, продублирую сюда выжимку, что сохранилось. Итак, как работает мув-семантика в нормальном языке (а не в плюсах):

use std::vec;
#[derive(Debug)]
struct Arrays<'a>{
    embedded: [i32; 2], // embedded slice
    borrowed: &'a [i32], // borrowed slice
    vector: Vec<i32> // slice on heap
}
#[derive(Debug)]
struct S<'a> {
    a: Arrays<'a>,
    b: i32
}
fn main() {
    let slice = [3, 4, 5];
    let a = Arrays{
        embedded: [1, 2],
        borrowed: &slice,
        vector: vec![6,7,8,9]
    };
    println!("created: {:?}, &embedded={:p}, &borrowed={:p}, &vector={:p}", &a, &a.embedded[0], &a.borrowed[0], &a.vector[0]);
    let b = S{a: a, b: 0};
    println!("moved: {:?}, &embedded={:p}, &borrowed={:p}, &vector={:p}", &b, &b.a.embedded[0], &b.a.borrowed[0], &b.a.vector[0]);
    let boxed = Box::new(b);
    println!("boxed: {:?}, &embedded={:p}, &borrowed={:p}, &vector={:p}",
        &boxed, &boxed.a.embedded[0], &boxed.a.borrowed[0], &boxed.a.vector[0]);

}

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

Ну и твой, онанимус, пример с созданием unique_pointer с использованием new, он как бы от твоей неграмотности. На современных плюсах это пишется так:

auto p = std::make_unique<int[]>(100);

Оператор new[] тут не нужен. Вообще если функция (или конструктор) должна завладеть памятью в хипе, передавать в неё сырой указатель нельзя. Во-первых, это некрасиво. Во-вторых, если она бросит исключение, память утечёт. Или не утечёт. Вызывающий код, даже если он поймает исключение, понятия не имеет, должен ли он освободить память сам. Поэтому люди, умеющие в плюсы, придумали правило: для передачи владения хиповым объектом нужно либо передавать параметром умный указатель, который в случае чего освободит ресурс сам, либо передавать параметры для создания объекта, и позволить функции создать объект самой.

Поэтому, мой юный друг, new/delete и называются низкоуровневыми возможностями. Они нужны где-то в кишках библиотечных классов, чтоб подарить тебе высокоуровневые удобные и надёжные инструменты. Вообще, язык C++ имеет огромное число недостатков и ровно одно достоинство: автоматический вызов деструкторов и и сделанное на его основе RAII. Так пользуйся им, а не колхозь.

И книжку купи. Тебе необходима.

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

Ну всё как я и говорил - дошколёнок будет делать вид, что ничего не было, хотя без проблем может посмотреть удалённые. Прежде чем блеять, тебе нужно обосновать свой кукаретинг про мув - https://godbolt.org/z/f41qcahac. Это в контексте изваяний «Во-первых, а с чего собственно возникла идея, что в безопасном расте должен быть аналог операции new T[size]? В расте для этого есть человеческий мув.»

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

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

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

Чего там смотреть? Кроме повторённого я высказывал оценку твоим умственным способностям и знанию не только Раста но и плюсов, а также предлагал тебе научиться внятно формулировать свои мысли. Я вот до сих пор не уверен что понимаю, что ты мне пытаешься доказать ссылками типа «https://godbolt.org/z/f41qcahac» и доказательства чего от меня хочешь получить. Ты осознай, что голоса у тебя в голове слышишь только ты, остальным приходится догадываться.

Это в контексте изваяний «Во-первых, а с чего собственно возникла идея, что в безопасном расте должен быть аналог операции new T[size]? В расте для этого есть человеческий мув.»

Ты, чучело, объединил 2 высказывания из разных контекстов. Человеческий мув в расте есть для того чтоб спокойно перенести структуру за пределы скоупа. Не нужно колхозить конструктор переноса ради этого.

А насчёт new T[size] я тебе уже объяснял. Такая конструкция используется в плюсах ради 2х разных вещей. Иногда она означает «зарезервируй мне память для массива на куче, а я потом заполню» и для этого в расте есть Vec::with_capacity(size). Без вектора тут было бы небезопасно. Иногда она означает «создай массив из элементов T» и тогда это 2 строчки, Vec::new() и resize(size, value); Как видишь, проблемы нет никакой. Ну а дальше ты понёс какую-то околесицу про то что это не Раст, но чем тебе этот код не нравится не пояснил.

https://godbolt.org/z/f41qcahac

И? Вот что из этого говна я должен почерпнуть, что тебе объяснить? Что сказать-то хотел? Что структуры в Расте могут содержать слайсы известного на момент компиляции размера? Да, могут. И я тебе демонстрировал. Что мув в Расте сделан по-человечески, через memcpy, а не через дебильные свопы, как в плюсах? Да, это преимущество нормального языка, где мув поддерживается компилятором, а не колхозится руками на основании дополнительного типа ссылок.

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

Ты вообще сам то что на С пишешь? Кто по жизни будешь?

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

а я потом заполню» и для этого в расте есть Vec::with_capacity(size). Без вектора тут было бы небезопасно.

Это есть не в расте, а С++ откуда ты это украл. Это хак для получения неинициализированной памяти, потому как иначе получить память без инициализации в С++ было нельзя. Какое отношение к этому имеешь ты, вор?

К тому же это работает для push, а не RA, поэтому в С++ это уже давно пытаются починить.

Так же - это не является zerocost, но у тебя её итак нет, правда непонятно почему вор и другие воры воруют себе ещё и zerocost.

resize(size, value); Как видишь, проблемы нет никакой.

Здесь есть проблемы. Ты украл вектор, но не украл емплейс. Ввиду того, что у тебя нет pnew, полиморфизма и нормальной системы типов. А это значит, что вначале value создаётся, а потом копируется в хип. Тебе ТС тебе показывал пруфы. Создаёшь vec, где T больше 8метров и получаешь so.

И? Вот что из этого говна я должен почерпнуть, что тебе объяснить? Что сказать-то хотел? Что структуры в Расте могут содержать слайсы известного на момент компиляции размера? Да, могут.

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

И я тебе демонстрировал.

Нет.

Что мув в Расте сделан по-человечески, через memcpy

Никакого мув в расте и раста нет. Раст это огрызок ворованный огрызок сишки, поэтому там сделано так как в сишке и С++. Дак вот, в С/С++ мув сделан именно через memcpy, откуда ты украл и мув и memcpy.

а не через дебильные свопы, как в плюсах?

Ни через какие свопы никакой мув в плюсах не реализуется. Реализуется кастомный мув, но он реализуется как угодно. Хоть через memcpy хоть через что другое.

Дефолтный мув, который ты украл - это memcpy. И да, ты опять опозорился. Ты рассказывал куллстори о том, что копирование и мув - это разное. Теперь, когда тебя взяли за жопу ты начал рассказывать «я имел ввиду не то».

Да, это преимущество нормального языка, где мув поддерживается компилятором, а не колхозится руками на основании дополнительного типа ссылок.

В очередной раз позорище несёт херню. Типы ссылок никакого отношения к муву не имеют. Никакого языка у тебя нет и в нём не может ничего, чего бы не было в С/С++, потому что сворован на базе ворованного С/С++-компилятора. И мув - это свойство С/С++, базовое и его компилятора.

Со ссылками позорище так же опозорилось, потому как ссылки не имеют никакого отношения к муву, о чём я уже сказал выше. Ссылки имеют отношение к полиморфизму, которого у тебя нет.

И именно потому, что в С++ такие ссылки есть - емплейс есть, а у тебя нет.

Кстати, ещё одно. Это позорище постоянно кукарекает о «безопасно», но вот в чём проблема. Это балаболище никто не просить показать safe аналог емплейса/pnew. Ведь ему ничего не мешало воровать указатели, которые небезопасные. Воровать аллокатор. А тут вдруг нельзя, а чего так?

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

Это есть не в расте, а С++ откуда ты это украл. Это хак для получения неинициализированной памяти, потому как иначе получить память без инициализации в С++ было нельзя. Какое отношение к этому имеешь ты, вор?

Никакого. Не воровал векторов никогда. Даже если ты под кражей подразумеваешь подсматривание идеи, в Rust я вектор не добавлял. Или ты уже меня с командой разрабов Rust отождествил?

Кстати, псевдоцарь, а ты в курсе, что STL была реализована изначально на Ada. Подозреваю, что вектор, как самый простой контейнер, там уже был. Так что по твоим же принципам, это C++ вектор украл.

Так же - это не является zerocost, но у тебя её итак нет, правда непонятно почему вор и другие воры воруют себе ещё и zerocost.

Ты мне напоминаешь клоунов-джавистов, которые прочитали в методичке state of art garbage collector и потом этот «state of art» в каждом споре вставляли. У тебя вместо этого zerocost.

Предположим, у нас есть T с дефолтным конструктором, выделяющим небольшой буфер. И ты, вместо использования вектора, пишешь твоё любимое new T[N], а потом заполняешь массив создаваемыми особым способом объектами. Это будет зерокост? А если это не будет зерокост, то чего ты тогда мозги паришь насчёт недостатка аллокации массивов в Расте?

А это значит, что вначале value создаётся, а потом копируется в хип.

Ну и хорошо. Собственно любой конструктор представляет собой функцию, которая дрючит переменные в регистрах и на стеке и потом пишет результат в память. Стек поэтому всегда в кэше. Вот, в Расте в худшем случае будет использовано на несколько байт в стеке больше и потом аккуратно последовательным копированием перенесено в результирующее место. Если не страдать структурками по мегабайту то ущерб от этого минимальный. И не факт что вообще есть, возможно что факт последовательного memcpy позволит процессору грамотно запись разрулить.

Создаёшь vec, где T больше 8метров и получаешь so.

Ну так не создавай T больше 8 метров. Зачем тебе такое? У тебя язык специализирующийся на мувах структур, каким надо быть дебилом чтоб делать структуру, мув которой будет создавать проблемы? Помести эти 8 метров в хипе и пусть они там лежат и не движутся при муве структурки.

Никакого мув в расте и раста нет. Раст это огрызок ворованный огрызок сишки, поэтому там сделано так как в сишке и С++. Дак вот, в С/С++ мув сделан именно через memcpy, откуда ты украл и мув и memcpy.

Ну во-первых, как нет если «украли»? Если украли, значит уже есть. Насчёт плюсов - это неправда. Во-первых, в C мува вообще нет. В плюсах есть, но плохой, не через memcpy. Посмотри хоть как сделан мув в векторе. А всё почему? Потому что конпелятор плюсов не умеет в мувы, он не знает, что мувнутое мувнулось, он вызовет у мувнутого деструктор. Соответственно приходится ручками это обходить и твой любимый зерокост от этого становится печальным.

В Расте наоборот, там компилятор увидит, что источник перемещён и не позволит к нему снова обращаться и даже не вызовет деструктора, поэтому можно оставлять там мусор. А если компилятору из кода статистически непонятно, переместилось оно или сохранилось, он заведёт переменную в флажком.

Типы ссылок никакого отношения к муву не имеют.

Как не имеют, болезный? Ещё как имеют. Поэтому в плюсах некоторые ссылки требуют особой реализации конструктора переноса и оператора присваивания переноса. А в Расте аналогичные им Box спокойно мувается с помощью memcpy.

Со ссылками позорище так же опозорилось, потому как ссылки не имеют никакого отношения к муву, о чём я уже сказал выше. Ссылки имеют отношение к полиморфизму, которого у тебя нет.

Полиморфизм в Расте тоже есть. И статический и динамический. Может книжку хоть прочитаешь?

И именно потому, что в С++ такие ссылки есть - емплейс есть, а у тебя нет.

Слушай, емплейс - это такая мелкая и сраная оптимизация, что на неё плевать с высокой колокольни. По идее её даже в язык не стоит добавлять, было бы хорошо чтоб компилятор во время LTO эту хрень разруливал. И емплейс никак не связан со ссылками, он скорее связан с конструкторами, вот без конструктора в Расте действительно емплейс сделать сложно. Не то что бы нельзя, но пришлось бы добавлять особый тип ссылки, ссылку на неинициализированную память, чтоб компилятор, видя её, следил чтоб в данную память писали, но из неё не читали.

Кстати, ещё одно. Это позорище постоянно кукарекает о «безопасно», но вот в чём проблема. Это балаболище никто не просить показать safe аналог емплейса/pnew. Ведь ему ничего не мешало воровать указатели, которые небезопасные. Воровать аллокатор. А тут вдруг нельзя, а чего так?

Ещё раз, болезный. Раст не запрещает использовать ансейф. Никто из разработчиков Раст не говорит, что когда-нибудь мы допилим язык до состояния, когда в нём не будет ансейфа. Цель Раста - предоставить возможности, которые работают в сейф коде. И тут одно из двух, либо ты поддерживаешь эту идею и тогда должен признать, что Раст - молодец, или не поддерживаешь, тогда изволь клеймить тот же плюсовый вектор. А то у тебя срань получается, вектор в плюсах хороший, а в Расте плохой, потому что «украли» и потому что «а внутре у него всё равно ансейф».

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

Никакого. Не воровал векторов никогда. Даже если ты под кражей подразумеваешь подсматривание идеи, в Rust я вектор не добавлял. Или ты уже меня с командой разрабов Rust отождествил?

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

Кстати, псевдоцарь, а ты в курсе, что STL была реализована изначально на Ada. Подозреваю, что вектор, как самый простой контейнер, там уже был. Так что по твоим же принципам, это C++ вектор украл.

Нет, никакой ада там нет и ни на какой аде это реализовать невозможно. И уж тем более stl - это дерьмо.

Кстати, балабол, ты опять обгадился с псевдоцарём.

Ты мне напоминаешь клоунов-джавистов, которые прочитали в методичке state of art garbage collector и потом этот «state of art» в каждом споре вставляли. У тебя вместо этого zerocost.

Т.е. зерокоста у тебя нет, я правильно понял?

Предположим, у нас есть T с дефолтным конструктором, выделяющим небольшой буфер. И ты, вместо использования вектора, пишешь твоё любимое new T[N], а потом заполняешь массив создаваемыми особым способом объектами. Это будет зерокост? А если это не будет зерокост, то чего ты тогда мозги паришь насчёт недостатка аллокации массивов в Расте?

Чего ты нисёшь, пришибленный. Какой new, какой вектор. Макака, мы сравниваем вектор вс статический массив, который ты не можешь создать в хипе, потому что твоя недоязычок дерьмо. Ты совсем кукареку?

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

Опять опозорился. Конструкторов у тебя нет - ты их не смог украсть. И нет, в нормальном яызке, который ты пытался своровать - это не так работает.

Стек поэтому всегда в кэше.

Полная и нелепая чушь. Ты в очередной раз опозорился.

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

Каких байт, макака? Чего ты несёшь? Тебе показал ТС кейс. Есть массив в 9 метров - его нужно записать в вектор. У тебя твоё дерьмо в принципе не запуститься с дефолтным стеком и отвалится на so. Не говоря о том, что ты будешь копировать эти 9 метров.

Ну и сказки про байты - это уровень. Нам нужно заполнить вектор байт пусть на 2 гига. Ты будешь заполнять его не 2 гигами, а 4-8, сколько там в твоём балабольстве будут несколько байт.

И никакой кеш о котором ты где-то что-то слышал тебе не поможет.

Если не страдать структурками по мегабайту то ущерб от этого минимальный. И не факт что вообще есть, возможно что факт последовательного memcpy позволит процессору грамотно запись разрулить.

Опять какая-то шизофазия. Процессор в принципе не может разлить memcpy, особенно на мегабайт. Позорище лсное.

Ну так не создавай T больше 8 метров. Зачем тебе такое? У тебя язык специализирующийся на мувах структур, каким надо быть дебилом чтоб делать структуру, мув которой будет создавать проблемы? Помести эти 8 метров в хипе и пусть они там лежат и не движутся при муве структурки.

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

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

Ещё раз, болезный. Раст не запрещает использовать ансейф. Никто из разработчиков Раст не говорит, что когда-нибудь мы допилим язык до состояния, когда в нём не будет ансейфа. Цель Раста - предоставить возможности, которые работают в сейф коде. И тут одно из двух, либо ты поддерживаешь эту идею и тогда должен признать, что Раст - молодец, или не поддерживаешь, тогда изволь клеймить тот же плюсовый вектор. А то у тебя срань получается, вектор в плюсах хороший, а в Расте плохой, потому что «украли» и потому что «а внутре у него всё равно ансейф».

Отвечу на эти потуги.

Ещё раз, болезный. Раст не запрещает использовать ансейф.

Запрещает. Идём на сайт этой бездарной скриптухи. Читаем:

Rust is blazingly fast and memory-efficient: with no runtime or garbage collector, it can power performance-critical services, run on embedded devices, and easily integrate with other languages.

Что методичка блеет? Нет рантайма? В векткоре он есть. performance-critical? Данная макака нам сообщает «ну какая разница зерокост там, либо не».

Далее читаем:

Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time.

Что блеет данная обезьяна?

Раст не запрещает использовать ансейф

использовать ансейф != guarantee, guarantee != ансейф. Ансейф не может ничего гарантировать.

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

Цель Раста - предоставить возможности, которые работают в сейф коде.

Ты не предоставил. Тебе показывают - ты блеешь «ну подумаешь 100500 копирований», «ну подумаешь там нет емплейса».

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

А вот тут ты перданул в лужу. Потому что выше я доказал(да и не только я), что ты украл огрызок вектора, а не вектор. Т.е. вектора нет.

А то у тебя срань получается, вектор в плюсах хороший, а в Расте плохой, потому что «украли» и потому что «а внутре у него всё равно ансейф».

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

В С++ это не проблема, потому что С++ не заявляет ни о каких гарантиях и ни о какой безопасноит. Поэтому там небезопасно и ансейф можно, а у тебя нельзя.

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

Что методичка блеет? Нет рантайма? В векткоре он есть. performance-critical? Данная макака нам сообщает «ну какая разница зерокост там, либо не».

Псевдоцарь, ты бредишь. Во-первых, ты явно под «рантаймом» понимаешь что-то своё. Во-вторых, если уж ты взялся доказывать что я соврал, нужно приводить что-то серьёзнее чем свои фантазии. Я утверждаю: «ансейф - часть языка Rust, никто не говорит, что он исчезнет». Ты должен привести опровержение этих слов, а не текст, который создал у тебя впечатление, что создатели Раста предложили тебе серебряную пулю.

использовать ансейф != guarantee, guarantee != ансейф. Ансейф не может ничего гарантировать.

Ты хотя бы одно предложение распарсить умеешь?

Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time.

Понимаешь, дурачок? A и B гарантируют C и D. Если пользуешься A и B то получишь C и D. Если не пользуешься, то не получишь. Я не знаю, если я напишу, что использование unique_ptr гарантирует своевременное освобождение памяти, ты мне ответишь «враньё, если я напишу new int[1000] то ничего не освободится»?

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

Ты не предоставил. Тебе показывают - ты блеешь «ну подумаешь 100500 копирований», «ну подумаешь там нет емплейса».

Опять споришь с Растом в моём лице? Царь, конечно, сумасшедший, но ты переигрываешь.

Про копирования и емплейс - да, «подумаешь». Вот GC - это не «подумаешь», а несколько байт скопировано - это ерунда.

Потому что выше я доказал(да и не только я), что ты украл огрызок вектора, а не вектор. Т.е. вектора нет.

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

В расте плохой, потому что а) ты блеешь «в расте сделали», а на самом деле украли.

Да, я тоже считаю что Царь смешной. Но шутку слишком часто повторять не стоит.

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

Нет, никакой ада там нет и ни на какой аде это реализовать невозможно. И уж тем более stl - это дерьмо.

В Аде дженерики в начале 70х были. И Степанов начинал свои поползновения именно с Ады.

Кстати, балабол, ты опять обгадился с псевдоцарём.

Нет, ты вряд ли Царь. Я с Царём лично не знаком, но говорят он плюсы знает. Ты не знаешь. Я в принципе могу поверить, что дурачок типа Царя может решить, что make_unique - это для школоты, а настоящие суровые мужики используют new. Но невозможно знать что-то о современных плюсах и ни разу не слышать о рекомендации не использовать new/delete в пользовательском коде. Ты же со своими «а покажи» явно о таком услышал впервые.

Т.е. зерокоста у тебя нет, я правильно понял?

Конечно есть. Просто не то, что ты понимаешь под этим. Зерокост, придуманный плюсовиками, означает «ты не платишь за то чем не пользуешься». И он относится к библиотечным особенностям. Если, скажем, компилятор не умеет векторизовать код или выравнивать поля структур, это не значит, что в компиляторе пропал «зерокост». Вот взять вектор, push_back может вызвать повторное выделение памяти и вызов конструкторов копирования для всего содержимого, освобождение памяти, а выделение памяти может потребовать пробежки по списку свободных кусков. Но вектор всё равно называют зерокостом потому, что, с точки зрения говорящего, лишней работы не делается. В рамках такого определения в Расте - зерокост.

Каких байт, макака? Чего ты несёшь? Тебе показал ТС кейс.

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

Хочешь я докажу, что плюсы - говно, ровно таким же принципом? Достаточно просто на shared_ptr создать двусвязный граф и потом пожаловаться, что память течёт, а на java такой же код не течёт, следовательно плюсы - говноязык.

Есть массив в 9 метров - его нужно записать в вектор. У тебя твоё дерьмо в принципе не запуститься с дефолтным стеком и отвалится на so.

Ты бы не писал о чём не знаешь. В расте нет конструктора вектора принимающего массив. Тем более принимающего его по значению, чтоб в стек пихать. Ты превратишь массив в итератор и запустишь на нём функцию collect. Collect спросит о размере, так как итератор массива размер знает, будет зарезервировано достаточно места и вектор заполнится, а массив исчезнет. Ты вообще реально думал, что такой идиот как ты за 5 минут найдёт дыру в языке, разработанном умными людьми?

Опять какая-то шизофазия. Процессор в принципе не может разлить memcpy, особенно на мегабайт. Позорище лсное.

Про префетчи не слышал? Современные процессоры с многоуровневыми кэшами очень много сил тратят на работу с этим говном. За последовательный доступ они очень благодарны.

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

Нет, ты вряд ли Царь.

Ты не поверишь…

что make_unique - это для школоты

Ты не поверишь (x2)

о рекомендации не использовать new/delete в пользовательском коде.

Кто тебе про пользовательский код сказал, бездарь?

ТС показал кейс. Ему объяснили, что он написал чушь и такая задача решается другими средствами.

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

Нет, побежала мне писать функцию которая понимает либо мув, либо ссылку. И имеет разное поведение в зависимости от r/lvalue.

Ты, видимо, не в курсе, что в расте полиморфизм реализуется через трейты. Погугли.

Тебя кто-то спрашивал про трейты? Функцию пиши.

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

Вот и реализуй. Жду.

Siborgium ★★★★★
()

Какой хороший тред. Эталонный.

peregrine ★★★★★
()

Rust и создание больших массивов

Читай документацию. Руст не предрпологает создание больших массивов.

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

Мне лень комментировать всё бездарное блеяние этого клоуна. Это первое, что я увидел:

Понимаешь, дурачок? A и B гарантируют C и D. Если пользуешься A и B то получишь C и D. Если не пользуешься, то не получишь. Я не знаю, если я напишу, что использование unique_ptr гарантирует своевременное освобождение памяти, ты мне ответишь «враньё, если я напишу new int[1000] то ничего не освободится»?

A и B гарантируют C и D. Если пользуешься A и B то получишь C и D. Если не пользуешься, то не получишь.

Тупая макака, во-первых нигде об этом не говорится - это A&B являются свойством говнораста - это декларируется, т.е. говнораста без A&B не существует.

Во-вторых, я не просто так спастил две цитаты. Говнораст декларируется как: «Rust is blazingly fast and memory-efficient:» - здесь нет «раст без A&B», как блеешь ты.

Таким образом выбор всё тот же.

Ах ну и да, макака доказала, что С++ даёт такие же гарантии. Просто не пользуйся тем, что опасно. Будут всё те же гарантии.

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

Кто тебе про пользовательский код сказал, бездарь?

О, ещё один сектант сишечки нарисовался. Вот что показательно, ни один вменяемый программист на плюсах (а их всё ещё много) не пойдёт плюсы защищать. Все понимают, что язык плохой. Защитники только из тех, кто вместо «здрасьте» пишут «бездарь».

Так вот, ответ тебе: да, мне сказали. Хотя я мог бы и сам догадаться, так как пример типа foo(new int[N], bar()), где bar() бросает исключение особого ума не требует. Ну т.е. любому сишнику известен прикол с foo(i++, i++) и из этого сделать вывод о том, как может вести себя foo(new int[N], bar()). И ты мог бы догадаться сам. И дальше одно из двух: либо ты дурак и так не понял, даже после объяснения, почему подобный код писать не следует. Либо ты считаешь всех дураками, т.е. типа ты понимаешь опасность утечки через new, но искренне веришь, что никто кроме тебя об этом не знает и поэтому рекомендации избегать new никогда не было.

ТС показал кейс. Адепты так и не решили проблему, но напредлагали убогого говна,

«не запихивай в структуру массив, пользуйся вектором» - это «убогое говно»? Ты - идиот.

Тебя кто-то спрашивал про трейты? Функцию пиши.

Сколько заплатишь?

Вот и реализуй. Жду.

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

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

Мне лень комментировать всё бездарное блеяние этого клоуна. Это первое, что я увидел:

Клоун, ты сколько лет в интернете? Такое пишут когда кажется, что среди аргументов есть 1 слабый, и поэтому ты типа остальное не читал.

упая макака, во-первых нигде об этом не говорится - это A&B являются свойством говнораста - это декларируется, т.е. говнораста без A&B не существует.

Давай, давай, натягивай сову на глобус. Клоун, ты слит. Вообще идея «я придумаю абсурдную интерпретацию чужих слов и раскритикую её» - это пример из демагогии известный тысячелетиями. Но люди с минимальным интеллектом прекращают на strawman настаивать после того как попались. Ты - другое. Ты будешь жопу рвать чтоб доказать, что тебе известно что хотели сказать люди, которые умнее тебя, и что именно идиотская интерпретация сказанного и есть правильная.

Но ты, клоун, забыл вырезать одну часть из цитаты. Поэтому я всё-таки заострю на ней внимание и прошу тебя ответить. Итак, если фанат плюсов утверждает, что плюсы хороши, в них есть unique_ptr который гарантирует однократное освобождение памяти, это правда? Да или нет? И является ли вменяемым возражением на это «ты врёшь, я написал auto ptr = new int[1000]; и потом память утекла»? Перед тем как ты напишешь очередную чушь на тему «мне обещали…» примени эти аргументы вот к описанному случаю.

Ах ну и да, макака доказала, что С++ даёт такие же гарантии. Просто не пользуйся тем, что опасно. Будут всё те же гарантии.

Перевожу с идиотского на русский: «возможно написать программу без ошибок на C++». Да, это правда. Можно и на ассемблере. Разница с Растом в том, что в Расте компилятор следит, чтоб ты не допускал некоторый класс ошибок. И да, эту защиту можно обойти, но случайно ты этого не сделаешь.

khrundel ★★★★
()

Царь прийди и растоклоунов накажи

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

Просто не пользуйся тем, что опасно. Будут всё те же гарантии

На практике это можно сократить до просто непользуйся C++, так как нет режимов компилчтора при которых компилировалось бы только безопасное подмножество языка. В будущем (наверно к 29 стандарту) надеюсь такое все же появится.

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

Ладно, раз поддельный царь расстроился, что не смог прочитать моё сообщение, продублирую сюда выжимку, что сохранилось. Итак, как работает мув-семантика в нормальном языке (а не в плюсах):

Т.е. ты берёшь какие-то очевидные оптимизации и называешь это мувом?

struct S {
    int a = 5;
    int b = 6;
};
struct Q {
    S s;
    int v;
};
void fn() {
    S s;
    Q q{s, 4};
    cout << q.s.a;
}

fn():
        movl    $5, %esi
        movl    $_ZSt4cout, %edi
        jmp     std::basic_ostream<char, std::char_traits<char> >::operator<<(int)

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

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