Reputation: 1017
I have a struct that stores a raw pointer to some data:
struct Foo<T> {
x: *const T
}
impl<T> Foo<T> {
fn new(x: &[T]) -> Foo<T> {
Foo {
x: &x[0] as *const T
}
}
}
The data is actually a slice, but I use the offset method to avoid directly storing the data. The constructor puts the a pointer to the data into the field, and returns the struct. However, if I try to return a Foo
from a function:
fn foo() -> Foo<i32> {
let x = [1, 2, 3];
Foo::new(&x)
}
fn main() {
unsafe {
println!("{}", &*foo().x);
}
}
The data is dropped too early, and the field x
points to garbage. What I want to have happen is the data x
points to is cloned, and the clone lives for as long as the struct does. How can I accomplish this?
Upvotes: 2
Views: 1012
Reputation: 59095
You don't.
You're trying to escape a pointer to stack data, which is something Rust would forbid you from doing if you were using regular borrowed pointers. However, by using raw pointers and unsafe
, you've effectively stripped off the various protections the compiler would normally enforce.
You really, really shouldn't be using unsafe
unless you understand what's happening.
You also cannot extend the lifetime of something created within a function without moving it out. There is simply no way of passing out a pointer (or a borrow) of x
.
The fix for this is to just not do it in the first place. Use borrowed pointers (&i32
or &[i32]
) or owned values (i32
, Vec<i32>
).
Another possibility would be to allocate the necessary storage in the caller and pass a &mut
into foo
, which you can then slice, mutate, and return a borrowed sub-slice to. That, of course, requires that you can statically define an upper-bound on how much space foo
will need, but such is life without std
.
Upvotes: 4