#How Box smart pointers works internally
84 messages · Page 1 of 1 (latest)
Where do you see rustc_box? Box has some special behavior like that dereferencing can consume the box. This is done with the #[lang = "owned_box"] attribute (this is a bulit-in attribute, not a macro, and only allowed in the standard library). But for the most part it's just a pointer that allocates in its constructor and deallocates in its drop. There might be some optimizations that only Box can do, and it has some special API rules (see https://doc.rust-lang.org/reference/special-types-and-traits.html#boxt), but other than that you can create your own box that does the same thing.
Btw here's a minimal version of the Box in std https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#example-implementing-a-box
#[rustc_box] basically replaces the following expression with a call to alloc, but with some optimizations
@pliant driftHere's a simple version of Box that I wrote just now https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=bdca5966860d87754437f3c2f29b6f79
The built-in Box has some functionality that is built into the compiler, so not everything can be emulated with user code, but hopefully my implementation can give you some idea of what's needed for most of the functionality.
(I haven't bothered to make it deallocate everything properly if Drop panics though. I'm too lazy for that lol)
(Also, it's untested.)
As for the #[rustc_box] thing, if you look at the source code for the nightly version of rust, you'll see that they've removed #[rustc_box]. Box now instead uses a #[rustc_intrinsic] instead to construct itself. https://doc.rust-lang.org/nightly/src/alloc/boxed.rs.html#240
It's an intrinsic in order to prevent Box::new on large arrays from copying stuff around too much, especially in debug mode.
Thanks bro for this
Hi can you explain what's the use of into_inner f(x)
pub fn into_inner(self) -> T {
unsafe {
let this = ManuallyDrop::new(self);
let value = this.0.read();
let layout = Layout::new::<T>();
if layout.size() != 0 {
dealloc(this.0.as_ptr().cast(), layout);
}
value
}
}
``` in this code your are dropping the struct itself and the pointer and then returning the value
This
If x is a built-in Box<String>, then doing y = *x will move the String out of the Box, leaving a Box with an uninitialized allocation behind.
It is impossible to emulate this in a user-defined type. Therefore, I opted to define a method that does the same thing.
Plz tell with simple words
For the built-in Box, you can move things out of the Box with the * operator.
For my type, you have to call into_inner.
Oh i see
I cannot make my type work like Box in this way.
Got it
Can I change the value pointed by box..?
Ig why it's impossible cause deref trait in rust don't allow to pass the ownership insted it allows only that reffrence of that value
To modify the value that the Box points to, you can use the fact that it implements DerefMut.
To make the box point to a new place, make a new Box and discard the old one.
Yes. We don't have a version of Deref that allows moving.
Got it
Got it thanks bro you explained things very simply ♥️
pub fn into_inner(self) -> T {
unsafe {
let this = ManuallyDrop::new(self);
let value = this.0.read();
let layout = Layout::new::<T>();
if layout.size() != 0 {
dealloc(this.0.as_ptr().cast(), layout);
}
value
}
}
``` in this code your are dropping the struct and the pointer and then returning the value
Am I correct.??
I'm taking the T out of the allocation. (This does not drop the T.) Then, I deallocate the heap memory. Then, I return the T that I got.
One more querry why you used ManualDrop??
Also why with self
If I didn't, then self would be dropped at the end of the function. This would drop the T after it's been moved out, causing a use after free.
But self will be moved.??
By this function
So what's the need to Use ManualDrop
The function gains ownership of self. The function ends, and self ends with it.
Oh
But what's the purpose of ManualDrop cause as per docs it's used to controll the automatic drop mechanism of rust
When something goes out of scope, it's automatically dropped.
If a ManuallyDrop goes out of scope, instead of dropping the thing inside, it does nothing.
Exactly what I wana say
But what's the need of that
In this case
.??
Because I want to disable the drop thing
But why
Because I already moved away the T. If self is dropped again, the Drop impl will call drop_in_place on the T
What do you mean by "is been moved now"?
When is it moved?
I hope this makes some sence if I am not wrong
.read() doesn't move self.
.as_ptr() doesn't move self
Then, the function ends. Since self hasn't been moved elsewhere, it would be dropped. Except I used ManuallyDrop to prevent that.
the function itself moves the self into_inner(self) // here self is moved
Actually I am noob I know something new is going to come I am ready for that
What into_iter are you talking about?
Sorry my mistake
What does this screenshot mean?
Sorry
For that too
I mean
If we
Are dropping the self what's the disadvantage in that..?
Also it's been moved
When we drop self, it calls the Drop impl.
Ah my small brain got it
I guess if you don't prevent dropping you basically double free since into_inner already frees the allocation
Sorry what if we just remove from into_inner rs if layout.size() != 0 { dealloc(this.0.as_ptr().cast(), layout); } then I guess there is no need to use ManualDrop cause as the value goes out of scope drop will be called and the value will be freed up
That doesn't work. The problem is the drop_in_place call
If you don't get frustrated by my questions can you explain why it will create the problem
Cause when I tried your code by commenting it out all worked fine no error
You drop_in_place the T. Then you return the T. The caller of into_inner uses the T, except it's already dropped.
Lol got it
It only causes issues if you do something like make a MyBox<String>
Hn I tried it with a int