RUST所有权实现

推荐《深入RUST标准库》,已经全网发售,恳请支持

fn main() {
    struct Point {x: f32, y: f32,};
    let p1 = Point{x:1.0, y:2.0};
    let p2 = p1; 
  }

这里p2的地址是否等于p1? 实测的结果是不等于。这样的话,等号的作用实际就是做了一个浅拷贝。如果等号右边的变量没有实现Copy,那等号右边的变量会被标记,如果后面再没有绑定其他,则被drop。
这个就是转移所有权的操作,所有权转移实质是一个浅拷贝加上原变量被标记。理解这个对于理解所有权是比较关键的。如果以为所有权转移是通过指针方式实现的,那会对很多RUST代码产生疑惑,也对所有权的理解产生困惑。
ptr::write<T>(dst: *mut T, src: T) 代码如下:


write函数本质上就是一个所有权转移的操作。完成src到dst的浅拷贝,然后调用了forget(src), 这使得src的Drop不再被调用(也规避src类型如果有引用导致的重复释放问题)。从而将所有权转移到dst。此函数是mem::replace, mem::transmute_copy的基础。底层由intrisic:: copy_no_overlapping支持。
这个函数中,如果dst已经初始化过,那原dst变量的所有权将被丢失掉,有可能引发内存泄漏。
再举一个例子,标准库中mem::replace的例子
相关代码如下:

pub const fn 
replace<T>(dest: &mut T, src: T) -> T {
    unsafe {
        // ptr::read复制了一个T,此时dest变量所有权出现了双份
        let result = ptr::read(dest);
        // src复制到dest上,src的所有权转移到dest,同时write函数调用了
        //forget函数,完成了所有权的转移。
        ptr::write(dest, src);
        result
    }
}

//此函数会复制一个变量,如果类型T含有引用或智能指针,仅仅调用这个函数会可能导致内存重复释放问题,
pub const unsafe fn read<T>(src: *const T) -> T {` 
        //利用MaybeUninit::uninit申请未初始化的T类型内存
        let mut tmp = MaybeUninit::<T>::uninit();
        //SAFETY: the caller must guarantee that `src` is valid for reads.
        // `src` cannot overlap `tmp` because `tmp` was just allocated on
        // the stack as a separate allocated object.
        //
        // Also, since we just wrote a valid value into `tmp`, it is guaranteed
        // to be properly initialized.
        unsafe {
            //完成内存拷贝
            copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
            //初始化后的内存移出ManuallyDrop 并返回
            tmp.assume_init()
        }
}
    
pub const unsafe fn write<T>(dst: *mut T, src: T) {
    unsafe {
        //浅拷贝
        copy_nonoverlapping(&src as *const T, dst, 1);
        //必须调用forget,这里所有权已经转移。不允许再对src做drop操作
        intrinsics::forget(src);
    }
}

伴随mem::replace而来的就是所有权的疑问。请见代码中的分析。 函数中dest变量的所有权会赋给返回值,而src的所有权会转移给dest。对以上如果掌握了,那就掌握了rust的所有权。

所有权转移后,需要深拷贝的内存指针都转移到浅拷贝后的结构变量里,如果原有的变量还在,则容易出现悬垂指针等一系列错误。这是采用所有权的原因。复杂结构的相等操作或拷贝操作需要细致实现,用一个简单的等号会使得程序员极易忽视这个操作需要花费的心血,因为省事而导致bug。使用所有权默认禁止掉复杂结构的多份浅拷贝,不但解决隐患,也使得程序员养成更良好的设计和编码质量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任成珺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值