2

私は 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
}

p_fooフィールドは、内の値barを指すように構築されるか、存在する場合はヌル ポインタになります。SomefooNone

もちろん、ここでの問題は、値Cachedが移動される場合、ストレートmemcpyは不適切であり、bar.p_fooさらにリダイレクトする必要があるということです。bar.p_fooこれは、定義可能な移動セマンティクスを備えたC++で簡単に保証できますが、Rustは「使用されるまで設定しない」以外の解決策を提供しますか? そのようにすることは確かに機能しますが、これらのキャッシュされた値が再利用される以上に (またはそれに近い頻度で) 移動されるとは思いません。これらを設定するには少し作業が必要です。特にネスト/チェーンが深い/長い場合。Boxまた、ヒープ上にサブ構造を配置したくありません。


明確にするために、Rustで複製したいC++で書くことができるものを次に示します。

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;
};
4

1 に答える 1

1

通常のデータ構造を実装するためではなく、安全なデータ構造を実装するために生のポインタがあるため、Rust に相当するのは生のポインタを使用しないことです。

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

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

Anは、型であり特性ではない限り、Option<Box<T>>a と (メモリ内のビット単位で) 正確に等しいことが保証されます。唯一の違いは、Rust 内で安全に使用できることです。*const TT

この方法では、もはや構造体は必要ありませCachedんが、オブジェクトを直接渡すことができBarます。


また、下位構造をヒープにボックス化しない方がよいでしょう。

次に、Barオブジェクトを保持するのではなく、オブジェクトを 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,
        }
    }
}

これらのポインターを設定するには、特にネスティング/チェーンが深い/長い場合に少し作業が必要です。

それは時期尚早の最適化のように聞こえます。ベンチマークしていない場所は最適化しないでください。

于 2016-03-24T08:33:00.217 に答える