defuz
defuz

Reputation: 27611

How to return a pointer to owned value that "does not live long enough"?

I have the following code:

struct Node {
    id: uint
}

struct Graph {
    nodes: Vec<Node>
}

impl Graph {

    fn new() -> Graph {
        return Graph { nodes: Vec::new() };
    }

    fn create_node(&mut self) -> &Node {
        let index = self.nodes.len();
        let node = Node { id: index };
        self.nodes.push(node);
        // return &node;           // error: `node` does not live long enough
        return &self.nodes[index]; // ...but this work fine
    }

}

The idea is that the graph creates a new node and "lends" it to someone who calls the method. But I can not figure out how to return a reference to the newly created structure. The second return is working fine, but obviously not effective.

How to return a node without taking it back from the vector?

Upvotes: 0

Views: 964

Answers (2)

Francis Gagn&#233;
Francis Gagn&#233;

Reputation: 65752

Here's why you can't return &node:

fn create_node(&mut self) -> &Node {
    let index = self.nodes.len();
    let node = Node { id: index };
    println!("{}", &node as *const Node);
    self.nodes.push(node);
    println!("{}", &self.nodes[index] as *const Node);
    return &self.nodes[index];
}

Here's a sample output:

0x7fffc36a3418
0x7f4c96c2d000

As you can see, &node and &self.nodes[index] return completely different values. Moreover, &node (0x7fffc36a3418) will be invalid as soon as create_node returns, because this address points to create_node call frame, and a call frame is freed when a function returns.

Upvotes: 2

Vladimir Matveev
Vladimir Matveev

Reputation: 127781

But I can not figure out how to return a reference to the newly created structure.

You can't. This is one of the basic errors which are ruled out by the ownership system.

Suppose you could. Then when your function returns such reference will point to destroyed memory.

You can read more on ownership in the official guide on ownership. It explains how ownership and borrowing work, including why your program is incorrect.

BTW, unless you have #[derive(Copy)] on your Node, taking a reference to node won't work also because node is moved into the vector. Ownership guide explains move semantics as well.

Upvotes: 2

Related Questions