mem::forget(mem::uninitialized()) 是定义的行为吗? [英] Is mem::forget(mem::uninitialized()) defined behavior?
问题描述
在 mutagen 中,我注入了各种代码中的突变.我想改变的一件事是模式如果让 Ok(x) = y { .. }
.然而,这带来了相当大的挑战,因为我无法知道 y
的类型——用户可以使用一元 Ok
变体.对于我们遇到的情况,我仍然可以机会性地对其进行变异实际上有一个 Result
其错误类型使用 trait 实现了 Default
看起来像下面的简化:
In mutagen, I'm injecting various
mutations in the code. One thing I'd like to mutate is the pattern
if let Ok(x) = y { .. }
. However, this poses quite the challenge, as I
cannot know the type of y
– the user could have built their own enum with an
unary Ok
variant. I can still opportunistically mutate it for cases where we
actually have a Result
whose error type implements Default
using a trait
that looks like the following simplified:
#![feature(specialization)]
pub trait Errorer {
fn err(self, mutate: bool) -> Self;
}
impl<X> Errorer for X {
default fn err(self, _mutate: bool) -> Self {
self
}
}
impl<T, E> Errorer for Result<T, E>
where
E: Default,
{
fn err(self, mutate: bool) -> Self {
if mutate {
Err(Default::default())
} else {
self
}
}
}
唉,实现Default
的错误并不多,所以这是不太有用.甚至 Result
的实现也会给出我们更加物有所值(并且完全有可能).然而,鉴于我不太关心代码实际上检查错误,我想知道我是否可以通过将上述代码的mutation扩展为
Alas, there aren't that many errors which implement Default
, so this is
not too useful. Even an implementation for Result<T, Box<Error>>
would give
us more bang for the buck (and be completely possible). However, given that I
don't care much about code actually inspecting the error, I wonder if I could
do a general implementation by extending the mutation of the above code to
match Errorer::err(y, mutation) {
Ok(x) => { .. }
Err(x) => { mem::forget(x); }
}
并让 err
在变异时返回 Err(mem::uninitialized())
– 这也是行为安全吗?注意:我从一个方法返回 Err(mem::uninitialized())
,只是在以后 mem::forget
它.我看不出这会引起恐慌,所以我们应该假设该值确实会被遗忘.
and have err
return Err(mem::uninitialized())
when mutating – so is this
behavior safe? Note: I'm returning Err(mem::uninitialized())
from a method,
only to mem::forget
it later. I see no way this could panic, so we should
assume that the value will be indeed forgotten.
这是明确的行为还是我应该期待鼻恶魔?
Is this defined behavior or should I expect nasal demons?
推荐答案
不,这不是定义的行为,至少不是所有类型.(我不知道你的代码将如何作为变异的一部分被调用,所以我不知道你是否可以控制这里的类型,但是通用的 impl
确实让它看起来像你做的不是.)下面的一段代码证明了这一点:
No, this is not defined behavior, at least not for all types. (I can't tell how your code would be called as part of mutation, so I don't know if you have control over the types here, but the generic impl
sure makes it look like you do not.) That's demonstrated by the following piece of code:
#![feature(never_type)]
use std::mem;
fn main() {
unsafe { mem::forget(mem::uninitialized::<!>()) }
}
如果您在操场上运行此程序,您将看到程序以 SIGILL 结束.ASM 输出显示 LLVM 只是将整个程序优化为立即 SIGILL,因为它使用无人居住类型 !
的值:
If you run this on the playground, you will see the program die with a SIGILL. The ASM output shows that LLVM just optimized the entire program to immediate SIGILL because of the way it uses a value of the uninhabited type !
:
playground::main:
ud2
一般来说,在通用代码中正确使用 mem::uninitialized
几乎是不可能的,参见例如本期rc::Weak
.因此,该函数正在弃用和替换.但这对你没有帮助;你想要做的对于 Result
来说是完全非法的.
Generally speaking, it is near impossible to correctly use mem::uninitialized
in generic code, see e.g. this issue of rc::Weak
. For this reason, that function is in the process of being deprecated and replaced. But that won't help you here; what you want to do is just outright illegal for Result<T, !>
.
这篇关于mem::forget(mem::uninitialized()) 是定义的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!