rust - Rust 中的 move 语义

标签 rust move-semantics ffi dangling-pointer

我正在用 Rust 包装一个 C 库,它的许多函数通过指向结构的指针获取参数,这些结构本身通常具有指向其他结构的指针。为了减少开销,我想提供将 Rust 数据编码到 C 结构中的结果缓存的能力。

这是 C 库如何期望一些参数的示例:

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar {
    p_foo: *const Foo,
    z: bool
}

以及我想象的拥有“缓存”版本的样子:

struct Cached {
    foo: Option<Foo>,
    bar: Bar
}

barp_foo 字段将被构造为指向 foo 中的 Some 值,或者一个 null如果有 None 的指针。

当然,这里的问题是,如果要 move Cached 的值,直接的 memcpy 是不合适的,bar.p_foo 还需要重定向。这在 C++ 中很容易确保,因为它具有可定义的 move 语义,但是 Rust 是否提供了除了“在使用之前不要设置 bar.p_foo”之外的解决方案?虽然这样做肯定会奏效,但我不认为这些缓存值的 move 频率会超过(甚至接近)它们被重用的频率,而且设置这些缓存值需​​要做一些工作指针,特别是如果嵌套/链接很深/很长。我也不希望 Box 堆上的子结构。


澄清一下,这是我可以用 C++ 编写的,我想在 Rust 中复制:

struct Foo {
    int x;
    float y;
};

struct Bar {
    Foo const*pFoo;
    bool z;
};

// bear with me while I conjure up a Maybe for C++
class Cached {
public:
    // would have appropriate copy constructor/assignment

    Cached(Cached &&other) {
        m_foo = other.m_foo;
        m_bar = other.m_bar;

        if(m_foo.isJust()) {
            m_bar.pFoo = &m_foo.value();
        } // else already nullptr
    }

    // similar move assignment

private:
    Maybe<Foo> m_foo;
    Bar m_bar;
};

最佳答案

Rust 等价物是不使用原始指针,因为原始指针用于实现我们的安全数据结构,而不是用于实现普通数据结构。

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar {
    p_foo: Option<Box<Foo>>,
    z: bool
}

Option<Box<T>>保证与 *const T 完全相同(以内存中的位为单位) ,只要T是一种类型而不是特征。唯一的区别是它可以在 Rust 中安全使用。

这样你甚至不需要 Cached结构,但可以直接绕过 Bar对象。


I'd also rather not Box the substructures up on the heap.

那我建议你不要保留Bar object around,而是在需要将一个传递给 C 时想起来它:

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar<'a> {
    p_foo: Option<&'a Foo>,
    z: bool
}

struct Cached {
    foo: Option<Foo>,
    z: bool,
}

impl Cached {
    fn bar<'a>(&'a self) -> Bar<'a> {
        Bar {
            p_foo: self.foo.as_ref(),
            z: self.z,
        }
    }
}

there is a bit of work involved to set up these pointers, especially if the nesting/chaining is deep/long.

这听起来很像过早的优化。不要在没有进行基准测试的地方进行优化。

关于rust - Rust 中的 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36188870/

相关文章:

rust - 是否可以下载以前的夜间构建?

C++11,返回 vector 函数风格的 move 语义

c++ - 在 C++ 中,返回时使用 move 操作是什么意思?

haskell - 如何使用 hsc2hs 绑定(bind)常量、函数和数据结构?

ruby - 使用 Ruby 2.5 安装 Jekyll

c - 如何调用函数 glMultiDrawElements::GLenum -> GHC.Ptr.Ptr GLsizei -> GLenum -> GHC.Ptr.Ptr (GHC.Ptr.Ptr a) -> GLsizei -> IO ()

functional-programming - 有没有更好的功能方法来处理带有错误检查的向量?

rust - 具有可变引用的递归结构中的生存期

rust - 如何限制关联类型接受任何引用生命周期?

c++ - 右值引用参数的正确默认值是多少?