【问题标题】:Moved object doesn't have same address [duplicate]移动的对象没有相同的地址[重复]
【发布时间】:2020-05-23 07:25:32
【问题描述】:

我认为从一个绑定移动到另一个绑定的对象仅仅意味着对象位本身保持不变;只是该程序源使用不同的绑定(标识符)引用它。

use std::fmt;

struct Person {
  name: String,
  age: u8,
}

impl Clone for Person {
  fn clone(&self) -> Self {
    Person {
      name: self.name.clone(),
      age: self.age,
    }
  }
}

impl fmt::Pointer for Person {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let ptr = self as *const Self;
    fmt::Pointer::fmt(&ptr, f)
  }
}

fn main() {
  let p = Person {
    name: "Krishna".to_string(),
    age: 8,
  };
  println!("{:p}", p);

  let a = p.clone();
  println!("{:p}", a);

  let q = p; // moved
  println!("{:p}", q);
}

打印出来

0x7ffee28b4178  // P
0x7ffee28b41f8  // A (P's clone)
0x7ffee28b4260  // Q (moved from P)

为什么pq的地址不一样?它是用rustc test.rs编译的。

【问题讨论】:

  • 如果你想要一个固定地址,这就是Pin 的用途
  • 仅仅通过使用他们的地址你可能不允许优化次数。
  • @Stargateur 当然,这只是一个更好地理解语言概念的玩具程序。谢谢!
  • 感谢您让我们知道Pin,但想要保持内存位置不变是另一回事。我想知道的是 Rust 的秘密行动。

标签: rust


【解决方案1】:

为什么p和q的地址不同?

Rust 对象不是堆分配的,因此,与 Python 或 Java 不同,binding 和它背后的实际对象之间没有区别。诸如p 之类的变量命名了对象实际存储的位置,因此移动对象也就不足为奇了。与 C++ 不同,Rust 不会在旧的(移动的)对象上运行析构函数,因此按位移动既正确又高效。

请注意,不能保证会发生实际移动。在优化的构建中,编译器很可能会意识到q 可以重用p 占用的空间并优化移动。正如 cmets 中所指出的,请求和使用地址可能会产生禁用此类优化的效果。

【讨论】:

  • 我是一名 C++ 程序员,我想我可以从自动变量(通常是堆栈分配)的角度来理解它。谢谢!
  • 我知道不可能进行简单的指针交换来进行移动,那么这里的移动是什么?编译器将如何为 Person 这样的自定义类型实现它?
  • @legends2k 它只是做了一个memcpy
  • @legends2k 像这样看:String 正好包含三个机器字:指向数据的指针、容量和长度。在您的情况下,String 以及这三个词是堆栈分配的,因此移动对象只会将它们逐字从一个堆栈位置复制到另一个堆栈位置。指向堆分配数据的指针将保持完全有效,因为堆上的数据将保持不变,并且移动是 O(1) 并且非常有效。它不会导致双重释放,因为与 C++ 不同,Rust 不会在旧的(移动的)对象上运行析构函数
  • @legends2k 所以在 Rust 中既可以移动也可以复制... - Rust 并没有自动调用复制构造函数。默认情况下会移动值,如果您想要一个副本,您必须通过调用clone() 明确请求它,之后克隆再次像往常一样移动。例外情况是实现 Copy 的对象,但这些对象被禁止具有析构函数,因此仅限于包含它们的数字和结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2016-03-16
  • 1970-01-01
  • 2019-04-05
  • 2015-09-21
相关资源
最近更新 更多