Memory (std.mem)
The std.mem module provides low-level memory allocation and manipulation functions.
nic
import std.mem;Allocation Functions
alloc
Allocate raw bytes:
nic
pub fn alloc(size: u64) -> opaque;nic
let buffer = std.mem.alloc(1024); // 1KB buffer
defer std.mem.dealloc(buffer);alloc_one
Allocate space for a single value of type T:
nic
pub fn alloc_one[T]() -> *T;nic
let ptr = std.mem.alloc_one[i32]();
defer std.mem.dealloc(ptr as opaque);
*ptr = 42;
println(int_to_string(*ptr));alloc_array
Allocate space for an array of values:
nic
pub fn alloc_array[T](count: u64) -> *T;nic
let arr = std.mem.alloc_array[i32](100);
defer std.mem.dealloc(arr as opaque);
for i in 0..100 {
arr[i] = i as i32;
}alloc_zeroed
Allocate zero-initialized memory:
nic
pub fn alloc_zeroed(count: u64, size: u64) -> opaque;nic
// Allocate 100 zero-initialized i32s
let arr = std.mem.alloc_zeroed(100, sizeof(i32)) as *i32;
defer std.mem.dealloc(arr as opaque);Deallocation
dealloc
Free previously allocated memory:
nic
pub fn dealloc(ptr: opaque) -> unit;Always pair allocations with deallocations, preferably using defer:
nic
let buffer = std.mem.alloc(1024);
defer std.mem.dealloc(buffer);
// Use buffer...
// Automatically freed when scope exitsReallocation
resize
Resize a previously allocated block:
nic
pub fn resize(ptr: opaque, new_size: u64) -> opaque;nic
let buffer = std.mem.alloc(100);
// Need more space
buffer = std.mem.resize(buffer, 200);
defer std.mem.dealloc(buffer);Memory Operations
copy
Copy bytes from source to destination:
nic
pub fn copy(dest: opaque, src: opaque, size: u64) -> unit;nic
let src = std.mem.alloc(100);
let dst = std.mem.alloc(100);
defer { std.mem.dealloc(src); std.mem.dealloc(dst); }
// Fill src with data...
std.mem.copy(dst, src, 100);set
Fill memory with a byte value:
nic
pub fn set(ptr: opaque, value: i32, size: u64) -> unit;nic
let buffer = std.mem.alloc(100);
defer std.mem.dealloc(buffer);
std.mem.set(buffer, 0xFF, 100); // Fill with 0xFFzero
Zero out memory:
nic
pub fn zero(ptr: opaque, size: u64) -> unit;nic
let data = std.mem.alloc(100);
defer std.mem.dealloc(data);
std.mem.zero(data, 100); // Clear to zerosBest Practices
Use new and release When Possible
For most allocations, prefer the built-in new and release:
nic
// Preferred for typed allocations
let point = new Point { x: 10, y: 20 };
defer release point;Use defer for Cleanup
Always use defer to ensure memory is freed:
nic
fn process_data() -> unit {
let buffer = std.mem.alloc(1024);
defer std.mem.dealloc(buffer);
// Even if we return early, buffer is freed
if some_condition {
return;
}
// Process buffer...
}Avoid Double-Free
Never free the same pointer twice:
nic
let ptr = std.mem.alloc(100);
std.mem.dealloc(ptr);
// std.mem.dealloc(ptr); // BUG: double-free!Check for Null
Allocation can fail (returns null):
nic
let buffer = std.mem.alloc(huge_size);
if buffer == nil {
println("Allocation failed!");
return;
}
defer std.mem.dealloc(buffer);