线程“ <main>”在Rust中溢出了其堆栈

VDi*_*mir 5 rust

我在尝试此代码时遇到错误,该代码实现了一个简单的链表。

use std::rc::Rc;
use std::cell::RefCell;

struct Node {
    a : Option<Rc<RefCell<Node>>>,
    value: i32
}

impl Node {
    fn new(value: i32) -> Rc<RefCell<Node>> {
        let node = Node {
            a: None,
            value: value
        };
        Rc::new(RefCell::new(node))
    }
}

fn main() {
    let first  = Node::new(0);
    let mut t = first.clone();
    for i in 1 .. 10_000
    {
        if t.borrow().a.is_none() { 
            t.borrow_mut().a = Some(Node::new(i));
        }
        if t.borrow().a.is_some() {
            t = t.borrow().a.as_ref().unwrap().clone();
        }
    }
    println!("Done!");
}
Run Code Online (Sandbox Code Playgroud)

为什么会发生?这是否意味着Rust不如定位的安全?

UPD:如果添加此方法,则程序不会崩溃。

impl Drop for Node {
    fn drop(&mut self) {
        let mut children = mem::replace(&mut self.a, None);

        loop {
            children = match children {
                Some(mut n) => mem::replace(&mut n.borrow_mut().a, None),
                None => break,
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我不确定这是否是正确的解决方案。

Dou*_*oug 5

这是否意味着Rust不如定位的安全?

防锈仅能防止某些类型的故障。特别是内存损坏崩溃,在此处记录:http : //doc.rust-lang.org/reference.html#behavior-considered-undefined

不幸的是,有时会出现一种趋势,即锈对于某些不会导致内存损坏的故障会更加强大。具体来说,您应该阅读http://doc.rust-lang.org/reference.html#behavior-considered-undefined

tldr; 生锈时,许多事情都会引起恐慌。紧急情况将导致当前线程停止执行关闭操作。

从表面上看,这可能看起来类似于其他语言的内存损坏崩溃,但重要的是要了解它虽然是应用程序故障,但不是内存损坏故障。

例如,您可以通过在不同线程中运行操作并在线程出现紧急情况时(无论出于何种原因)妥善处理失败,来处理与紧急情况类似的异常。

在此特定示例中,您正在堆栈上消耗过多的内存。

这个简单的示例也会失败:

fn main() {
  let foo:&mut [i8] = &mut [1i8; 1024 * 1024];
}
Run Code Online (Sandbox Code Playgroud)

(在大多数rustc上;取决于特定实现的堆栈大小)

我本以为使用Box :: new()将您的分配移动到堆栈将在此示例中解决此问题...

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug)]
struct Node {
    a : Option<Box<Rc<RefCell<Node>>>>,
    value: i32
}

impl Node {
    fn new(value: i32) -> Box<Rc<RefCell<Node>>> {
        let node = Node {
            a: None,
            value: value
        };
        Box::new(Rc::new(RefCell::new(node)))
    }
}

fn main() {
    let first  = Node::new(0);
    let mut t = first.clone();
    for i in 1 .. 10000
    {
        if t.borrow().a.is_none() {
            t.borrow_mut().a = Some(Node::new(i));
        }
        if t.borrow().a.is_some() {
            let c:Box<Rc<RefCell<Node>>>;
            { c = t.borrow().a.as_ref().unwrap().clone(); }
            t = c;
            println!("{:?}", t);
        }
    }
    println!("Done!");
}
Run Code Online (Sandbox Code Playgroud)

...但事实并非如此。我真的不明白为什么,但是希望其他人可以看一下这个问题,并发布一个更权威的答案,说明究竟是什么导致了代码中的堆栈耗尽。