How can I move a value out of the argument to Drop::drop()?
up vote
6
down vote
favorite
I'm using gfx-hal
, which requires me to create resources which need to be explicitly destroyed using functions specific to their type. I'd like to store instances of these types in structs, and I'd also like to tie cleaning them up to the lifetime of the owning struct, instead of managing their lifetimes manually and potentially having objects on the GPU/in the driver live forever.
However, all the functions in the destroy
family of functions take the type directly, rather than a reference, so when I try to pass them from my structs, I get errors like the following:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
It seems like there should be some way around this issue, as I'm currently in the Drop::drop
function itself, so self
is already "consumed." How do I get the instances of these types out of self
as T
, and not &T
?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
rust
add a comment |
up vote
6
down vote
favorite
I'm using gfx-hal
, which requires me to create resources which need to be explicitly destroyed using functions specific to their type. I'd like to store instances of these types in structs, and I'd also like to tie cleaning them up to the lifetime of the owning struct, instead of managing their lifetimes manually and potentially having objects on the GPU/in the driver live forever.
However, all the functions in the destroy
family of functions take the type directly, rather than a reference, so when I try to pass them from my structs, I get errors like the following:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
It seems like there should be some way around this issue, as I'm currently in the Drop::drop
function itself, so self
is already "consumed." How do I get the instances of these types out of self
as T
, and not &T
?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
rust
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Couldn't you use a NewType forT
that implementsDrop
and callsdestroy()
. That way, theDrop
forS
would be automatically generated.
– rodrigo
Nov 12 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@SvenMarnach: Oh, I see. I was assumingS
was some composite type. But then the NewType would be exactly like thisS
.
– rodrigo
Nov 12 at 11:02
add a comment |
up vote
6
down vote
favorite
up vote
6
down vote
favorite
I'm using gfx-hal
, which requires me to create resources which need to be explicitly destroyed using functions specific to their type. I'd like to store instances of these types in structs, and I'd also like to tie cleaning them up to the lifetime of the owning struct, instead of managing their lifetimes manually and potentially having objects on the GPU/in the driver live forever.
However, all the functions in the destroy
family of functions take the type directly, rather than a reference, so when I try to pass them from my structs, I get errors like the following:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
It seems like there should be some way around this issue, as I'm currently in the Drop::drop
function itself, so self
is already "consumed." How do I get the instances of these types out of self
as T
, and not &T
?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
rust
I'm using gfx-hal
, which requires me to create resources which need to be explicitly destroyed using functions specific to their type. I'd like to store instances of these types in structs, and I'd also like to tie cleaning them up to the lifetime of the owning struct, instead of managing their lifetimes manually and potentially having objects on the GPU/in the driver live forever.
However, all the functions in the destroy
family of functions take the type directly, rather than a reference, so when I try to pass them from my structs, I get errors like the following:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
It seems like there should be some way around this issue, as I'm currently in the Drop::drop
function itself, so self
is already "consumed." How do I get the instances of these types out of self
as T
, and not &T
?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
rust
rust
edited Nov 12 at 1:40
Shepmaster
145k11279413
145k11279413
asked Nov 12 at 0:33
Ben Pious
3,80611526
3,80611526
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Couldn't you use a NewType forT
that implementsDrop
and callsdestroy()
. That way, theDrop
forS
would be automatically generated.
– rodrigo
Nov 12 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@SvenMarnach: Oh, I see. I was assumingS
was some composite type. But then the NewType would be exactly like thisS
.
– rodrigo
Nov 12 at 11:02
add a comment |
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Couldn't you use a NewType forT
that implementsDrop
and callsdestroy()
. That way, theDrop
forS
would be automatically generated.
– rodrigo
Nov 12 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@SvenMarnach: Oh, I see. I was assumingS
was some composite type. But then the NewType would be exactly like thisS
.
– rodrigo
Nov 12 at 11:02
2
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Couldn't you use a NewType for
T
that implements Drop
and calls destroy()
. That way, the Drop
for S
would be automatically generated.– rodrigo
Nov 12 at 10:29
Couldn't you use a NewType for
T
that implements Drop
and calls destroy()
. That way, the Drop
for S
would be automatically generated.– rodrigo
Nov 12 at 10:29
1
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@SvenMarnach: Oh, I see. I was assuming
S
was some composite type. But then the NewType would be exactly like this S
.– rodrigo
Nov 12 at 11:02
@SvenMarnach: Oh, I see. I was assuming
S
was some composite type. But then the NewType would be exactly like this S
.– rodrigo
Nov 12 at 11:02
add a comment |
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
You could choose to use unsafe code with ManuallyDrop
and swap out the current value for an uninitialized one1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
See also:
- How to move one field out of a struct that implements Drop trait?
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
You could choose to use unsafe code with ManuallyDrop
and swap out the current value for an uninitialized one1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
See also:
- How to move one field out of a struct that implements Drop trait?
add a comment |
up vote
4
down vote
accepted
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
You could choose to use unsafe code with ManuallyDrop
and swap out the current value for an uninitialized one1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
See also:
- How to move one field out of a struct that implements Drop trait?
add a comment |
up vote
4
down vote
accepted
up vote
4
down vote
accepted
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
You could choose to use unsafe code with ManuallyDrop
and swap out the current value for an uninitialized one1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
See also:
- How to move one field out of a struct that implements Drop trait?
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
You could choose to use unsafe code with ManuallyDrop
and swap out the current value for an uninitialized one1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
See also:
- How to move one field out of a struct that implements Drop trait?
edited Nov 12 at 2:13
answered Nov 12 at 2:01
Shepmaster
145k11279413
145k11279413
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254645%2fhow-can-i-move-a-value-out-of-the-argument-to-dropdrop%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 at 2:07
Couldn't you use a NewType for
T
that implementsDrop
and callsdestroy()
. That way, theDrop
forS
would be automatically generated.– rodrigo
Nov 12 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 at 10:52
@SvenMarnach: Oh, I see. I was assuming
S
was some composite type. But then the NewType would be exactly like thisS
.– rodrigo
Nov 12 at 11:02