How can I move a value out of the argument to Drop::drop()?
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 |
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 '18 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 '18 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 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 '18 at 11:02
add a comment |
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 '18 at 1:40
Shepmaster
148k12285419
148k12285419
asked Nov 12 '18 at 0:33
Ben Pious
3,85011626
3,85011626
2
Looks like you're not the only one to find this frustrating: github.com/gfx-rs/gfx/issues/2452
– loganfsmyth
Nov 12 '18 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 '18 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 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 '18 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 '18 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 '18 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 10:29
1
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 at 10:52
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 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 '18 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 '18 at 11:02
add a comment |
1 Answer
1
active
oldest
votes
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 |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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 |
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 |
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 '18 at 2:13
answered Nov 12 '18 at 2:01
Shepmaster
148k12285419
148k12285419
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 '18 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 '18 at 10:29
1
@rodrigo Isn't that exactly what the OP was trying to do?
– Sven Marnach
Nov 12 '18 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 '18 at 11:02