2016-03-23 11 views
2

私はRustにCライブラリをラッピングしています。その関数の多くは、他の構造体へのポインタを持つ構造体へのポインタによってパラメータを受け取ります。オーバーヘッドを減らすために、RustデータをC構造体にマーシャリングした結果をキャッシュする機能を提供したいと思います。ここでRustのセマンティクスを移動する

は、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の値は、の値がfooであることを指すように、またはNULLポインタがNoneの場合は指すように構成されます。

Cachedという値を移動する場合、直線memcpyは不適切であり、さらにbar.p_fooはリダイレクトする必要があります。これは、定義可能な移動セマンティクスでC++で確実にすることは簡単ですが、使用するまで「bar.p_fooを設定しないでください」以外の解決策を提供していますか?このようにキャッシュされた値は、再利用されるよりも多く(またはそれに近い頻度でも)動かされるとは考えていません。これらの値を設定するには少しの作業が必要ですポインタ、特にネスト/チェインが深い/長い場合私はむしろBoxの部分構造をヒープ上に置いていません。明確にするために


は、ここで私はルーストに複製したい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; 
}; 
+0

*は、 'Cached'の値が移動された場合です* *私は十分な情報を提供していないようです。移動したときに無効になる 'bar.p_foo'へのポインタを保持するのは何ですか? [this](https://play.rust-lang.org/?gist=53bf026d76e0665e2381&version=stable)のようなものはまったく役に立ちますか? – Shepmaster

+0

'bar.p_foo' *は、オブジェクトが移動される場合に無効にされるポインタで、構造体自体の(部分の)フィールドを指します。私はC++で必要なものと同等のものを書くことで明確にします。 – jmegaffin

答えて

1

サビに相当するものは、生のポインタを使用しないことであろう私たちの安全なデータ構造を実装するためのものであり、通常のデータ構造を実装するものではありません。

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

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

Option<Box<T>>は限りTタイプとしない形質であるように、*const Tに(メモリ内のビットで)正確に同等であることが保証されます。唯一の違いは、Rust内で使用するのが安全だということです。

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


また、私はむしろ、ヒープ上の部分構造をアップにボックスではないと思います。

その後、私はあなたの周りBarオブジェクトを保持し、代わりにあなたがCに1を渡す必要があるたびにそれを想起させるしていないお勧め:

#[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, 
     } 
    } 
} 

に関連する作業のビットがありますこれらのポインタを設定します。特に、入れ子/連鎖が深い/長い場合は、これらのポインタを設定します。

早すぎる最適化のように聞こえます。ベンチマークしていない場所を最適化しないでください。