-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Potential generalization of destructing struct destructuring #713
Comments
I have a use case.. I'm trying to make polydimensional array DSTs, which is all well and good, but I would like to implement movable-reference semantics, which means making a The relevance to destructuring is I'd like to implement
So what this code does is it sets the drop flag to false and destructures, this way the referant is not dropped, then if the drop flag was true it returns a wrapper that always drops its content, and if it was false it returns the object responsible for allocating. Without this feature I would need to construct a new |
I run into this a lot with RAII wrapper types. A trivial example:
I've also seen it happen where, when dropping, I want to call It seems to me that, if |
@Lucretiel On nightly you can use |
I have stumbled onto an other use case for this feature, where pub struct Unescaper<'a> {
buf: &'a mut String,
old_len: usize,
has_errored: bool,
}
pub struct UnescaperError;
impl<'a> Unescaper<'a> {
pub fn new(buf: &'a mut String) -> Self {
Self {
old_len: buf.len(),
buf,
has_errored: false,
}
}
pub fn unescape_fragment(&mut self, fragment: &str) {
// unescape the content of the string fragment,
// write it to buf, and update internal state...
}
pub fn finish(self) -> Result<&'a str, UnescaperError> {
if self.has_errored {
// The Drop impl will clear out the partially unescaped string
Err(UnescaperError)
} else {
// Disable clear-on-drop and returns the unescaped string to the user
let this = std::mem::ManuallyDrop::new(self);
&this.buf[this.old_len..] // <--+
// |
// error: cannot return value referencing local variable `this`
}
}
}
// Clear what we've written out on drop
impl<'a> Drop for Unescaper<'a> {
fn drop(&mut self) {
self.buf.truncate(self.old_len)
}
} Currently, there is no way to write this without using unsafe code to transmute the lifetime of the returned buffer If destructuring was always allowed, and disabled the pub fn finish(self) -> Result<&'a str, UnescaperError> {
if self.has_errored {
Err(UnescaperError)
} else {
let Self { buf, old_len, .. } = self; // note: this disables clear-on-drop
&buf[old_len..]
}
} |
Issue by glaebhoerl
Monday Jan 27, 2014 at 21:17 GMT
For earlier discussion, see rust-lang/rust#11855
This issue was labelled with: in the Rust repository
Currently structs with destructors are (sensibly) not allowed to be move-destructured (#3147), because then when their destructor runs, it would access deinitialized values.
This could potentially be generalized if we recognize that a destructor, in other words drop glue, is not an indivisible thing. It consists of the
Drop
impl for the struct itself, and the destructors for each of its fields. Therefore if we write:when the destructuring happens we could run the
Drop
impl forS
, but not the drop glue forA
andB
. Those are then moved out, and their destructors will run later, whenever they go out of scope.I believe this is sound:
Drop::drop()
takes&mut self
, so it can mutate the components ofS
but not deinitialize them. If we broaden our considerations tounsafe
code, then if the fields of a structS
have destructors themselves, then theDrop
impl forS
must, even today, leave them in a valid state, because those destructors will then access it. It is only cases where the fields ofS
do not have their own destructors, and theDrop
impl forS
usesunsafe
code to put them in an invalid state, which would become dangerous, and we would have to be very careful about.We'd obviously have to think about whether we actually want this (I haven't thought of any use cases yet), but as a theoretical possibility, I think it checks out.
The text was updated successfully, but these errors were encountered: