我有一个对象,我知道它在 Arc
中,因为所有实例总是 Arc
ed。我希望能够在函数调用中传递我自己的克隆 Arc
。我正在调用的对象稍后会在其他线程上给我回电。
在 C++ 中,有一个名为 enable_shared_from_this
的标准 mixin。它使我能够做到这一点
class Bus : public std::enable_shared_from_this<Bus>
{
....
void SetupDevice(Device device,...)
{
device->Attach(shared_from_this());
}
}
如果此对象不受 shared_ptr
管理(最接近的 C++ 必须为 Arc
),那么这将在运行时失败。
我找不到等价物。
编辑:
这是一个为什么需要它的例子。我有一个定时器队列库。它允许客户端请求在将来的某个时间点运行任意闭包。该代码在专用线程上运行。要使用它,您必须传递要稍后执行的函数的闭包。
use std::time::{Duration, Instant};
use timerqueue::*;
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};
// inline me keeper cos not on github
pub struct MeKeeper<T> {
them: Mutex<Weak<T>>,
}
impl<T> MeKeeper<T> {
pub fn new() -> Self {
Self {
them: Mutex::new(Weak::new()),
}
}
pub fn save(&self, arc: &Arc<T>) {
*self.them.lock().deref_mut() = Arc::downgrade(arc);
}
pub fn get(&self) -> Arc<T> {
match self.them.lock().upgrade() {
Some(arc) => return arc,
None => unreachable!(),
}
}
}
// -----------------------------------
struct Test {
data:String,
me: MeKeeper<Self>,
}
impl Test {
pub fn new() -> Arc<Test>{
let arc = Arc::new(Self {
me: MeKeeper::new(),
data: "Yo".to_string()
});
arc.me.save(&arc);
arc
}
fn task(&self) {
println!("{}", self.data);
}
// in real use case the TQ and a ton of other status data is passed in the new call for Test
// to keep things simple here the 'container' passes tq as an arg
pub fn do_stuff(&self, tq: &TimerQueue) {
// stuff includes a async task that must be done in 1 second
//.....
let me = self.me.get().clone();
tq.queue(
Box::new(move || me.task()),
"x".to_string(),
Instant::now() + Duration::from_millis(1000),
);
}
}
fn main() {
// in real case (PDP11 emulator) there is a Bus class owning tons of objects thats
// alive for the whole duration
let tq = Arc::new(TimerQueue::new());
let test = Test::new();
test.do_stuff(&*tq);
// just to keep everything alive while we wait
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
}
cargo 运输
[package]
name = "tqclient"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
timerqueue = { git = "https://github.com/pm100/timerqueue.git" }
parking_lot = "0.11"
最佳答案
无法从 &self
到存储 self
的 Arc
。这是因为:
- 与 C++ 引用相比,Rust 引用具有额外的假设,这些假设会使此类转换成为未定义的行为。
- Rust 的
Arc
实现甚至没有公开确定self
是否存储在Arc
中所必需的信息。
幸运的是,还有一种替代方法。不是为 Arc
中的值创建 &self
并将其传递给方法,而是将 Arc
直接传递给需要的方法访问它。你可以这样做:
use std::sync::Arc;
struct Shared {
field: String,
}
impl Shared {
fn print_field(self: Arc<Self>) {
let clone: Arc<Shared> = self.clone();
println!("{}", clone.field);
}
}
那么print_field
函数只能在封装在Arc
中的Shared
上调用。
关于rust - C++ 的 shared_from_this 在 Rust 中的等价物是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63542263/