代码之家  ›  专栏  ›  技术社区  ›  Tim Diekmann suresh madaparthi

如何使用不安全代码在由RefCell/RwLock Ref/Guard封装的集合上返回迭代器?

  •  1
  • Tim Diekmann suresh madaparthi  · 技术社区  · 6 年前

    关于这一主题,已经提出了许多问题:

    不可能的 (没有不安全)。

    我自己也试过这种不安全的变体,想问问这条路是否安全。

    我的想法是把警卫包装在一个实现 Iterator . 除了保护之外,还存储了一个迭代器,迭代器将从存储的保护创建:

    struct MapIter<'a> {
        guard: RwLockReadGuard<'a, HashMap<i32, i32>>,
        iter:  Iter<'a, i32, i32>,
    }
    

    impl<'a> MapIter<'a> {
        fn new(map: &'a RwLock<HashMap<i32, i32>>) -> Box<Self> {
            // create a `box Self`
            // the iterator remains uninitialized.
            let mut boxed = Box::new(Self {
                guard: map.read().expect("ToDo"),
                iter:  unsafe { mem::uninitialized() },
            });
    
            // create the iterator from `box Self`.
            boxed.iter = unsafe { 
                (*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter() 
            };
            boxed
        }
    }
    

    现在它可以实现 迭代器

    impl<'a> Iterator for MapIter<'a> {
        type Item = (&'a i32, &'a i32);
    
        fn next(&mut self) -> Option<Self::Item> {
            self.iter.next()
        }
    }
    

    这个密码安全吗?

    请在 playground

    另外我得到一个 警告

    warning: trivial cast: warning: trivial cast: `&std::sync::RwLockReadGuard<'_, std::collections::HashMap<i32, i32>>` as `*const std::sync::RwLockReadGuard<'a, std::collections::HashMap<i32, i32>>`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
       |
       | unsafe { (*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter() };
       |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       |
    

    1 回复  |  直到 6 年前
        1
  •  4
  •   trent oli_obk    6 年前

    不,这不安全。我可以用 Container 要在安全代码中创建悬挂引用,请执行以下操作:

    let container = Container::new();       // create a container
    let r = {
        let mut it = container.iter();
        it.next()                           // obtain a reference to part of it
    };
    container.map.write().unwrap().clear(); // empty the container
    println!("{:?}", r);                    // oh dear.
    

    the playground 这是编译的,这不好,因为 r HashMap 已清除。

    Vladimir Matveev's answer to a similar question 更详细地解释为什么这是不合理的,并包含以下简明摘要:

    您不能这样做,因为这样可以避免运行时检查唯一性冲突。