Rust中指针
起因
今天学习一下Rust中的指针.
原生指针
//原生指针 *const (不可变) 和 *mut(可变)
let mut x = 32;
let y = &mut x; //引用
unsafe {
*y =64; //通过原生指针 修改值
}
引用
//引用 通过&和&mut
let a = 100;
let b = &a;
println!("a={}", b);
智能指针
智能指针最早在c++得到了应用.智能指针是RAII(资源获取即初始化)和作用域范围的完美结合,在离开所在作用域的范围的进行资源的释放.#ifndef ALGORITHM_MYCLASS_H
#define ALGORITHM_MYCLASS_H
#include <iostream>
using namespace std;
class MyClass
{
public:
char* p;
MyClass()
{
cout << "调用构造函数" << endl;
p = new char[1024 * 1024 * 100](); //在堆上分配100m的空间
}
~MyClass()
{
cout << "调用析构函数" << endl;
delete[] p; //在析构函数时,释放100m空间
}
};
#endif //ALGORITHM_MYCLASS_H
int main(int argc, char *argv[]) {
{
vector<int> vec1{1, 2, 3}; //①在任务管理器中看当前程序所占内存大小
unique_ptr<MyClass> myClass(new MyClass()); //unique_ptr 智能指针 在离开所在的作用域,自动释放资源
vector<int> vec2{1, 2, 3}; //②在任务管理器中看当前程序所占内存大小
}
cin.get(); //③任务管理器中看当前程序所占内存大小,
//得出结论: 通过智能指针给myClass在堆上进行内存分配,在离开所在的作用域后,自动调用析构函数,并释放资源
return 0;
}
进入正题,Rust中最典型的智能指针非Box和String莫属,String使用最多,Rust中的智能指针都会实现Drop(没实现Drop,不会自动释放资源,能叫智能)和Deref(没有*,能叫指针),在Rust中类型默认是分配栈上的,可以通过Box(有点像C#的装箱操作,在IL中使用box进行装箱操作)分配到堆上.具体看下面的示例代码:
fn main() {
{
let p1 = Point { x: 1 }; //是在栈上进行的内存分配
let point = Box::new(Point { x: 1 }); //通过Box的new函数在堆上开辟内存空间
//Box实现Drop trait在离开所在作用域自动内存
}
}
Box<T>源码,只有new/drop/deref.
/// A pointer type for heap allocation.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.
#[lang = "owned_box"] //编译器实现内存分配和释放 由于实现drop trait可以自动释放资源
#[fundamental]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Box<T: ?Sized>(Unique<T>);
impl<T> Box<T> {
/// Allocates memory on the heap and then places `x` into it.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline(always)]
pub fn new(x: T) -> Box<T> {
box x //box 在编译时,由编译器将box替换为exchange_malloc在离开作用域的是调用drop
}
}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized> Drop for Box<T> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
//由编译器生成 释放资源代码
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &T {
&**self
}
}
通过Rust编译器rustc,生成汇编代码,是可以看到exchange_malloc函数的,具体看下边生成的代码:
#通过--emit 可以指定 asm(汇编) llvm-ir(llvm中间代码) obj(目标文件)
rustc --emit asm .\test.rs
_ZN5alloc5alloc15exchange_malloc17h0cb71b2e0aa90f51E:
.seh_proc _ZN5alloc5alloc15exchange_malloc17h0cb71b2e0aa90f51E
subq $72, %rsp
.seh_stackalloc 72
.seh_endprologue
callq _ZN4core5alloc6layout6Layout25from_size_align_unchecked17hab6091c15e4a755eE
movq %rax, 48(%rsp)
movq %rdx, 40(%rsp)
leaq .L__unnamed_2(%rip), %rcx
movq 48(%rsp), %rdx
movq 40(%rsp), %r8
callq _ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h589e7297af27cd37E
movq %rdx, 64(%rsp)
movq %rax, 56(%rsp)
movq 56(%rsp), %rax
testq %rax, %rax
sete %cl
movzbl %cl, %edx
movl %edx, %eax
jne .LBB42_5
jmp .LBB42_7
.LBB42_7:
movq 48(%rsp), %rcx
movq 40(%rsp), %rdx
callq _ZN5alloc5alloc18handle_alloc_error17h96b5be050b7b98c9E
ud2
ud2
.LBB42_5:
movq 56(%rsp), %rcx
movq 64(%rsp), %rdx
callq _ZN4core3ptr8non_null26NonNull$LT$u5b$T$u5d$GT$10as_mut_ptr17h41487f386a6f2536E
movq %rax, 32(%rsp)
movq 32(%rsp), %rax
addq $72, %rsp
retq
.seh_handlerdata
.text
.seh_endproc
.def _ZN5alloc5alloc5alloc17ha8c49ddbf193d337E;
.scl 3;
.type 32;
.endef
.p2align 4, 0x90
_ZN5alloc5alloc5alloc17ha8c49ddbf193d337E:
秋风
2020-03-28