Форум программистов, компьютерный форум, киберфорум
Rust
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.79/19: Рейтинг темы: голосов - 19, средняя оценка - 4.79
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
1

Можно ли создать неинициализированный массив? Кроме как let arr: [Option<u8>; 3] = [None; 3];

27.06.2020, 13:03. Показов 3592. Ответов 34
Метки нет (Все метки)

Доброго времени суток. Пример на Си:
C
1
2
3
4
5
int main() {
    uint8_t arr[3];
    arr[0] = 42;
    printf("%d\n", arr[0]);
}
Создаётся неинициализованный массив, записывается одно значение и выводится.

Попробовал сделать подобное на расте без инициализации массива:
Код
fn main() {
    let mut arr: [Option<u8>; 3] = [None; 3];
    arr[0] = Some(42);
    println!("{}", arr[0]);
}
Что-то слишком сложно получилось и не работает. Может, не заморачиваться и всегда инициализировать массивы? let mut arr: [u8; 3] = [0; 3]; А если в массиве будет миллион элементов? Будет бессмысленно инициализировать их все нулём, если дальше по коду в массив буду гарантированно записаны данные. Даже питоновский numpy позволяется создавать неинициалидованные массивы: https://numpy.org/doc/stable/r... empty.html
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.06.2020, 13:03
Ответы с готовыми решениями:

Напишите функцию filterRange(arr, a, b), которая принимает массив arr, ищет в нём элементы между a и b
Здравствуйте! Всех с прошедшими праздниками! Сегодня, пишу с целью задать несколько вопросов....

[Visual c++] Можно ли как то создать форму в студии, кроме clr проекта?
Добрый день форумчане. Вопрос следующий, я хочу создать приложение на c++ в VisualStudio...

Проблемы с методом массива (Array.prototype.p=1 var arr=new Array(); arr.watch('p',alertme) arr.p=2)
Опять я с подобной проблемой. &lt;script language='JavaScript1.2'&gt; function...

Массив: Подскажите, пожалуйста, как передать массив А в процедуру Arr?
Добрый день! Подскажите, пожалуйста, как передать массив А в процедуру Arr? using System;...

__________________
34
║XLR8║
1105 / 852 / 256
Регистрация: 25.07.2009
Сообщений: 4,180
Записей в блоге: 5
27.06.2020, 13:14 2
Лучший ответ Сообщение было отмечено Рыжий Лис как решение

Решение

Рыжий Лис, nomicon

Unsafe Rust gives us a powerful tool to handle this problem: MaybeUninit. This type can be used to handle memory that has not been fully initialized yet.
2
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
27.06.2020, 13:23  [ТС] 3
Вроде, получилось:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use std::mem::{self, MaybeUninit};
 
fn main() {
    const SIZE: usize = 10;
    let x = {
        let mut x: [MaybeUninit<u32>; SIZE] = unsafe {
            MaybeUninit::uninit().assume_init()
        };
        // for i in 0..9 {
        //     x[i] = MaybeUninit::new(i as u32);
        // }
        unsafe { mem::transmute::<_, [u32; SIZE]>(x) }
    };
    dbg!(x);
}

Ничего не будет из-за того, что я Box убрал?
1
║XLR8║
1105 / 852 / 256
Регистрация: 25.07.2009
Сообщений: 4,180
Записей в блоге: 5
27.06.2020, 19:37 4
Лучший ответ Сообщение было отмечено Рыжий Лис как решение

Решение

Рыжий Лис, чтобы развеять сомнения по поводу UB и что это значит в расте, пообщался в дискорде. В общем, люди говорят что так будет работать:

C#
1
2
3
4
5
6
7
8
9
10
use std::mem::{self, MaybeUninit};
 
fn main() {
    const SIZE: usize = 100500;
    type U = u8;
    let x = unsafe { 
        mem::transmute::<[MaybeUninit<U>; SIZE], [U; SIZE]>(
            MaybeUninit::uninit().assume_init())
    };
}
Касательно бокса, люди говорят что это, мол, чтобы пример был не с примитивным типом данных.
2
Заблокирован
27.07.2020, 15:16 5
Политика безопасности Rust такова, что не допускает использование неинициализированных переменных. Если не важно где будут размещены данные - в стеке или в куче, - то правильнее и прошюще воспользоваться вектором, создав пустой вектор.
0
║XLR8║
1105 / 852 / 256
Регистрация: 25.07.2009
Сообщений: 4,180
Записей в блоге: 5
02.08.2020, 21:13 6
Цитата Сообщение от sodda Посмотреть сообщение
Политика безопасности Rust
В "Книге", по unsafe написано что компилятор не знает всех случаев когда код безопасен и, чтобы сказать компилятору что он дурак, надо использовать unsafe.
0
Заблокирован
04.08.2020, 17:38 7
Цитата Сообщение от outoftime Посмотреть сообщение
В "Книге", по unsafe написано что компилятор не знает всех случаев когда код безопасен и, чтобы сказать компилятору что он дурак, надо использовать unsafe.
И?
Создание неинициализированных переменных запрещено, так как это может привести к ряду проблем, которые Rust старается решить при помощи инструментов языка, а конкретно - создание висячих указателей. Если вы решились на это разместив код в блоке unsafe, то вам предупреждают, что вы делаете это на свой страх и риск. Unsafe для этого и создан.
0
║XLR8║
1105 / 852 / 256
Регистрация: 25.07.2009
Сообщений: 4,180
Записей в блоге: 5
14.10.2020, 04:19 8
Лучший ответ Сообщение было отмечено Рыжий Лис как решение

Решение

Рыжий Лис, недавно увидел ещё одно решение:
C++ (Qt)
1
2
let v = Vec::with_capacity(n);
unsafe { v.set_len(n); }
1
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
14.10.2020, 05:29  [ТС] 9
С небольшими правками заработало. Правда, это вектор. Но вектор тоже может пригодиться.
C#
1
2
3
    const SIZE: usize = 100500;
    let mut v: Vec<u8> = Vec::with_capacity(SIZE);
    unsafe { v.set_len(SIZE); }
0
Заблокирован
21.10.2020, 11:57 10
Вот в этой конструкции
Цитата Сообщение от outoftime Посмотреть сообщение
let v = Vec::with_capacity(n);
unsafe { v.set_len(n); }
вот это зачем?
C++ (Qt)
1
unsafe { v.set_len(n);}
0
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
21.10.2020, 12:01  [ТС] 11
Видимо, чтобы принудительно задать размер вектора (без инициализации памяти). Но надо читать документацию
0
Заблокирован
21.10.2020, 12:17 12
Цитата Сообщение от Рыжий Лис Посмотреть сообщение
Но надо читать документацию
Вот именно. Ибо это конструкция с точки зрения языка - бред.
0
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
21.10.2020, 12:24  [ТС] 13
В принципе, мои подозрения подтвердились:
Forces the length of the vector to new_len.

This is a low-level operation that maintains none of the normal invariants of the type. Normally changing the length of a vector is done using one of the safe operations instead, such as truncate, resize, extend, or clear.

Safety
new_len must be less than or equal to capacity().
The elements at old_len..new_len must be initialized.
0
Заблокирован
21.10.2020, 12:34 14
Рыжий Лис, capacity - это емкость вектора, то количество элементов которое вектор может вместить без перераспределения памяти.
Проще говоря, если вы создали вектор u8 ёмкостью 512 - то в куче выделен отрезок длинной 512 байт.
Length - длинна вектора - это количество присутствующих фактических элементов в векторе. Вы, допустим, создали вектор ёмкостью 512 байт и потом добавили в него 300 элементов и тогда длинна вектора будет равна 300, а ёмкость 512. Если вы добавите 513 элемент в вектор, то Rust создаст новый вектор длинной в 2 раза больше - 1024 - и копирует туда элементы из первоначального вектора.
В примере кода создается вектор ёмкостью 100500 байт, при этом его длинна равна нулю. Потом идет совершенно ненужная штука - set_len(), которая непонятно что делает. Скорее ничего не делает, так как длинна нулю равна и в векторе нет элементов вообще. Если бы в векторе было 512 элементов, а мы бы сделали set_len(300) - то логика понятна. И то эту функцию не рекомендуют использовать, так как она может приводить к утечкам памяти.
0
4135 / 2712 / 388
Регистрация: 01.06.2013
Сообщений: 5,713
Записей в блоге: 9
21.10.2020, 13:33 15
Цитата Сообщение от sodda Посмотреть сообщение
Потом идет совершенно ненужная штука - set_len(), которая непонятно что делает.
В векторе, кроме самих данных, хранится и его len - кол-во используемых элементов.
set_len устанавливает новое значение длины, которое потом можно посмотреть по len(), которое будет учитываться в дальнейшем для изменения capacity при добавлении элемента и пр.
Подразумевается, что len не должно меняться напрямую, но, для эффективности, это можно сделать с помощью set_len, но тут уж rust не может контролировать то, что вы творите.
В общем, эта штука - set_len() вполне понятно что делает.
1
Заблокирован
21.10.2020, 15:04 16
Цитата Сообщение от Curry Посмотреть сообщение
, которое будет учитываться в дальнейшем для изменения capacity при добавлении элемента и пр.
Каким образом?

Цитата Сообщение от Curry Посмотреть сообщение
что len не должно меняться напрямую
Естественно, так как это закрытое поле закрытой структуры - вектора.

Цитата Сообщение от Curry Посмотреть сообщение
В общем, эта штука - set_len() вполне понятно что делает.
Я написал, что непонятно что она делает в этом конкретном случае - при создании нового вектора с заданной ёмкостью.
если мы создали вектор определенной ёмкости, то предполагается, что мы знаем сколько будет элементов в векторе. Мы специально указали ёмеость, чтобы избежать перераспределения памяти. если не знаем, то создаем вектор без указания ёмкости. Не знаю каким боком тут нужно set_len(), особенно учитывая, что длинна не может быть больше ёмкости. Поэтому в документации и говорится о том, что нужно использовать функции вроде truncate

Добавлено через 45 минут
Curry, так, как я выше сказал, - это бред.
Ты создаешь вектор определенной емкости, потом тут же ставишь значение длинны равное значению ёмкости и при первом же добавлении элемента в этот вектор память перераспределяется, ёмкость увеличивается в два раза. Вот такие тут советчики.
А в векторе нули одни до определенного момента.

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
  let mut v: Vec<u8> = Vec::with_capacity(5);
  println!("cap = {}, len =  {}", v.capacity(), v.len());
 
  unsafe {
    v.set_len(5);
 };
v.push(1);
println!("cap = {}, len =  {}", v.capacity(), v.len());
 
for i in &v {
  print!("{}", i)
 }
}
cap = 5, len =  0
cap = 10, len =  6
000001
Добавлено через 20 минут
Возвращаясь к тому, почему в Rust "запрешено" использовать не инициализированные переменные.



C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main(void) {
  int a;
  //не инициализировали переменную сразу.
  //.......................
  //забыли присвоить этой переменной потом значение
  int* b = &a; 
  if ((*b) == 1) {
    printf("Все спокойно.\n");
  } else {
    printf("Ядерная ракета на старт!\n");
  }
  return 0;
}
кроме того, ссылка указывает на неизвестно куда - в какую-то область памяти, которая может принадлежать другому процессу в системе.

Добавлено через 2 минуты
Но если
C++ (Qt)
1
2
3
4
5
fn main() {
 
let v: Vec<u8> =  Vec::with_capacity(5);
let s = &v[0];
}
Вызовет панику и остановку программы.
0
4135 / 2712 / 388
Регистрация: 01.06.2013
Сообщений: 5,713
Записей в блоге: 9
21.10.2020, 15:36 17
Цитата Сообщение от sodda Посмотреть сообщение
так, как я выше сказал, - это бред.
Самокритичность, это -
Цитата Сообщение от sodda Посмотреть сообщение
память перераспределяется, ёмкость увеличивается в два раза.
Что именно в 2 раза, это не документировано и не всегда (хотя и чаще всего).
Можно помедитировать на исходник где память выделяется. Из push он вызывается с needed_extra_cap=1.
Цитата Сообщение от sodda Посмотреть сообщение
Вот такие тут советчики.
Нормальные советчики.
Цитата Сообщение от sodda Посмотреть сообщение
ссылка указывает на неизвестно куда - в какую-то область памяти, которая может принадлежать другому процессу в системе.
В вашем примере нет ссылки, а указатель указывает на вполне конкретную а. И большинство плюсовых (и сишных) компиляторов выдают warning в таком простом случае. Кроме того, IDE тоже подчёркивают неинициализированные переменные. Но, конечно, исключение такого поведения на уровне языка, это хорошо.
Цитата Сообщение от sodda Посмотреть сообщение
Вызовет панику и остановку программы.
Неужели?
И почему же?
1
Заблокирован
21.10.2020, 17:25 18
Цитата Сообщение от Curry Посмотреть сообщение
это не документировано
Ну это у вас, а у меня документировано.

Цитата Сообщение от Curry Посмотреть сообщение
и не всегда (хотя и чаще всего).
Когда нужно согласиться, но не очень хочется и ты соглашаешься, но как бы не до конца.

Цитата Сообщение от Curry Посмотреть сообщение
В вашем примере нет ссылки, а указатель указывает на вполне конкретную а.
Ды? А 'а' куда указывает?

Цитата Сообщение от Curry Посмотреть сообщение
И большинство плюсовых (и сишных) компиляторов выдают warning в таком простом случае.
Ну у меня что-то не выдал.

Цитата Сообщение от Curry Посмотреть сообщение
И почему же?
Попробуйте и сея тайна вам откроется.

Цитата Сообщение от Curry Посмотреть сообщение
Нормальные советчики.
я вижу
0
Просто Лис
Эксперт Python
4246 / 2656 / 911
Регистрация: 17.05.2012
Сообщений: 7,916
Записей в блоге: 9
21.10.2020, 17:30  [ТС] 19
Цитата Сообщение от sodda Посмотреть сообщение
Ды? А 'а' куда указывает?
Куда-нибудь на стек

Кстати, даже анализатор PVS-Studio молчит на сишный код https://www.viva64.com/ru/online-examples/
1
Заблокирован
21.10.2020, 17:57 20
Цитата Сообщение от Рыжий Лис Посмотреть сообщение
Куда-нибудь на стек
Только богу известно куда))
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.10.2020, 17:57

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Если можно создать массив TButton, то как создать массив их событий?
Пишу программу в которой много однообразных Едитов и кнопок. Чтобы &quot;облегчить сбе жизнь&quot; создал...

Объявите неинициализированный трехмерный массив и присвойте значения элементам с помощью кода
Объявите неинициализированный трехмерный массив и присвойте значения элементам с помощью кода 3...

можно ли и если можно, то как в сессии создать двумерный массив ?&
нужен сабж

Как вывести массив arr на экран до сортировки?
namespace ConsoleApp15 { class Program { static void Main(string args) ...

Массив: Как можно создать массив, не прописывая каждую строку, а с применением цикла?
Добрый день. Имеется массив: var priceList = { &quot;1644&quot; : {&quot;id&quot; : &quot;1644&quot;, &quot;subid&quot; : {},...

Синонимы операций взятия адреса массива (arr и &arr)
возможно коряво написал заголовок, да и сам вопрос банальный. после создании лок. массива его адрес...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.