• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

? Implements `Box<T>` and `Vec<T>` and why?

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
? What Is Box<T> (A Smart Help Pointer)?


Box<T> is a smart pointer that owns and stores its contents on the heap. It’s a core part of Rust’s ownership and memory management model, giving you fine control over data placement without sacrificing safety.

When you create a value with Box::new(x), Rust:

  1. Allocates memory on the heap
  2. Writes x into that memory
  3. Returns a Box<T> that points to the heap
✅ When to Use Box<T>

  • You need to store large data on the heap
  • You want to build recursive types (like trees or linked lists)
  • You’re working with trait objects and need dynamic dispatch (Box<dyn Trait>)
  • You want to transfer ownership safely across contexts
?️ A Simple Reimplementation of Box<T>


Want to know how Box<T> works internally? Here's a simplified, educational version:


use std::alloc::{alloc, dealloc, Layout};
use std::ptr::NonNull;

pub struct MyBox<T> {
ptr: NonNull<T>,
}

impl<T> MyBox<T> {
pub fn new(value: T) -> Self {
let layout = Layout:?:<T>();
let ptr = unsafe { alloc(layout) as *mut T };

if ptr.is_null() {
panic!("Allocation failed");
}

unsafe {
ptr.write(value);
}

MyBox {
ptr: unsafe { NonNull::new_unchecked(ptr) },
}
}

pub fn get(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}

impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
let layout = Layout:?:<T>();
unsafe {
std::ptr::drop_in_place(self.ptr.as_ptr());
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
? How It Works (Step-by-Step)

  • Layout:?:<T>() tells the allocator how much space to reserve
  • alloc() allocates raw heap memory
  • ptr.write(value) writes the value into that memory
  • NonNull<T> wraps the pointer for safety (non-null guarantee)
  • Drop is implemented to automatically clean up the memory when the box is dropped
? Example Use


fn main() {
let boxed = MyBox::new(99);
println!("Heap value: {}", boxed.get());
}
? Why This Matters for System Programming


Understanding how Box<T> is built gives you insights into:

  • Manual memory management (without garbage collection)
  • Why Rust avoids double frees and leaks
  • How to build your own allocators or smart pointers

And it’s especially critical for fields like:

  • Blockchain development
  • Operating system work
  • Embedded systems
  • Performance-critical network services
✅ Final Thoughts


Box<T> looks simple — but behind it is an elegant, powerful system for safely managing heap memory. Learning how it works isn't just an academic exercise: it’s one of the first steps to mastering real Rust systems programming.

“When you understand the memory, you control the performance.”
Why Vec<T> A Growable Heap Array ?


understanding how Vec<T> works under the hood is crucial. It's more than just a dynamic array: it's an efficient, memory-safe, growable buffer backed by heap memory. In this post, we’ll walk through what Vec<T> is, how it works, when to use it, and even how to reimplement a minimal version (MyVec<T>) to deepen your mastery.

? What Is Vec<T>?


Vec<T> is a growable, contiguous vector type that stores elements on the heap. It keeps track of:

  • A pointer to the buffer
  • The current length (len) — how many elements are initialized
  • The capacity — how many elements the buffer can hold before needing to grow

This is ideal for situations where:

  • You don’t know the size of your data at compile time
  • You want fast, indexed access
  • You may frequently add or remove elements
? What Happens When You Call push()?


When you call v.push(x), here’s what actually happens:

  1. If the length equals capacity, Rust grows the buffer (usually doubling the capacity)
  2. It calculates the address at ptr.add(len) — the next free slot
  3. It writes the value using unsafe pointer write (ptr.write(value))
  4. It increments len

pub fn push(&mut self, value: T) {
if self.len == self.capacity() {
self.grow();
}
unsafe {
let end = self.as_mut_ptr().add(self.len);
end.write(value);
}
self.len += 1;
}

Likewise, pop() just moves the length back by 1 and reads the last element from memory:


pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
unsafe {
let ptr = self.as_mut_ptr().add(self.len);
Some(ptr.read())
}
}
? Memory Layout of Vec<T>


Buffer: [10][20][30][_][_][_]
Index : 0 1 2 capacity = 6

len = 3
  • All values are stored contiguously
  • Insertions and deletions at the end are amortized O(1)
?️ Let’s Reimplement a Simplified MyVec<T>


Here’s a basic version of a vector that grows dynamically:


use std::alloc::{alloc, dealloc, realloc, Layout};
use std::ptr::NonNull;
use std::mem;

pub struct MyVec<T> {
ptr: NonNull<T>,
len: usize,
cap: usize,
}

impl<T> MyVec<T> {
pub fn new() -> Self {
MyVec {
ptr: NonNull::dangling(),
len: 0,
cap: 0,
}
}

pub fn push(&mut self, value: T) {
if self.len == self.cap {
self.grow();
}
unsafe {
let end = self.ptr.as_ptr().add(self.len);
end.write(value);
}
self.len += 1;
}

fn grow(&mut self) {
let (new_cap, new_layout) = if self.cap == 0 {
(4, Layout::array::<T>(4).unwrap())
} else {
let new_cap = self.cap * 2;
(new_cap, Layout::array::<T>(new_cap).unwrap())
};

let new_ptr = if self.cap == 0 {
unsafe { alloc(new_layout) as *mut T }
} else {
let old_layout = Layout::array::<T>(self.cap).unwrap();
unsafe { realloc(self.ptr.as_ptr() as *mut u8, old_layout, new_layout.size()) as *mut T }
};

self.ptr = NonNull::new(new_ptr).expect("allocation failed");
self.cap = new_cap;
}

pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
unsafe { Some(self.ptr.as_ptr().add(self.len).read()) }
}

pub fn get(&self, index: usize) -> Option<&T> {
if index >= self.len {
return None;
}
unsafe { Some(&*self.ptr.as_ptr().add(index)) }
}
}

impl<T> Drop for MyVec<T> {
fn drop(&mut self) {
unsafe {
for i in 0..self.len {
std::ptr::drop_in_place(self.ptr.as_ptr().add(i));
}
let layout = Layout::array::<T>(self.cap).unwrap();
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
✨ Why Study the Internals of Vec<T>?


Understanding how Vec<T> works teaches you:

  • How safe systems manage dynamic memory manually
  • Why Rust avoids buffer overflows, dangling pointers, and double frees
  • How real containers grow, shrink, and manage performance-critical memory

This is especially useful for Rust developers who want to:

  • Build high-performance tools
  • Write custom memory allocators or data structures
  • Work in blockchain, embedded, OS, or graphics domains
? Final Thoughts


By understanding Vec<T>, you’re not just using Rust — you’re learning how it thinks. You're seeing the boundaries between safe code and unsafe code — and how Rust lets you cross those lines carefully, with purpose.

“The more you understand how memory moves, the more power you have as a programmer.”
Stay curious. Try building your own vector. And the next time you call .push(), know exactly how it works behind the scenes.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу