汎用C ++ラッパーを使用してRustの所有権モデルを実現できますか?


15

Rustの並行処理の安全性に関するこの記事をご覧ください。

http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html

これらのアイデアのどれだけがC ++ 11(またはそれ以降)で達成できるのかと思っていました。特に、所有権を渡すメソッドに所有権を譲渡する所有者クラスを作成できますか?C ++には変数を渡す方法がたくさんあるので不可能だと思われますが、クラスまたはテンプレートにいくつかの制限を設けて、メソッドのパスごとにテンプレートコードが実行されるようにすることができますか?


リンクからのいくつかの引用は、この質問を改善するだろう
マーティンBa

2
@delnan(Safe)Rustは、一度に複数の可変参照を一度も持たず、読み取り専用参照も持っているものに対して可変参照を持たないことを保証します。また、スレッド間でデータを転送する際にいくつかの制限があります。これらを組み合わせることで、スレッド関連の重大なクラスのバグを防ぎ、シングルスレッドコードであってもオブジェクトの状態に関する推論を容易にします。
CodesInChaos

3
C ++コンパイラが検証できる方法で借用を表現できるとは思わないので、関連するパフォーマンスヒットを伴うランタイムの強制に頼らなければなりません。
CodesInChaos

1
スコープの所有権は、C ++ 11のスマートポインターによって既に実装されていませんか?
アクシャトマハジャン

1
@JerryJeremiah Rustには、さまざまな参照タイプがあります。基本的なものは&、使用するために何らかのプロモーションを必要としません。&mut同じアイテムへの別の参照(変更可能かどうか)をまだ取得しようとすると、コンパイルできなくなります。RefCell<T>チェックを実行時に移動するので.borrow_mut()、すでにアクティブな.borrow()またはを持っているものにしようとすると、パニックが発生します.borrow_mut()。RustにはRc<T>(共有所有ポインター)とその兄弟もWeak<T>ありますが、それらは可変性ではなく所有権に関するものです。可変性のためRefCell<T>にそれらの内側に貼り付けます。
8bittree

回答:


8

C ++には、値、左辺値参照、右辺値参照の3つの方法でパラメーターを関数に渡す方法があります。これらのうち、値渡しは、呼び出された関数が独自のコピーを受け取るという意味で所有権を作成し、右辺値参照渡しは、値が消費される可能性がある、つまり、呼び出し元によって使用されなくなることを示します。左辺値参照による受け渡しは、オブジェクトが呼び出し元から一時的に借用されることを意味します。

ただし、これらは「慣例により」である傾向があり、コンパイラが常にチェックできるとは限りません。また、を使用して、誤って左辺値参照を右辺値参照に変換できますstd::move()。具体的には、3つの問題があります。

  • 参照は、参照するオブジェクトよりも長く存続できます。Rustのライフタイムシステムはこれを防ぎます。

  • いつでも複数の可変/非定数参照をアクティブにすることができます。Rustのボローチェッカーはこれを防ぎます。

  • 参照をオプトアウトすることはできません。呼び出された関数のシグネチャを知らないと、その関数がオブジェクトへの参照を作成するかどうかを呼び出しサイトで確認できません。したがって、クラスの特別なメソッドを削除したり、「参照なし」スタイルガイドへの準拠について呼び出しサイトを監査したりしても、参照を確実に防ぐことはできません。

ライフタイムの問題は、基本的なメモリの安全性に関するものです。参照されるオブジェクトの有効期限が切れたときに参照を使用することはもちろん違法です。しかし、オブジェクト内に参照を保存するとき、特にそのオブジェクトが現在のスコープを超えているときは、ライフタイムを忘れがちです。C ++型システムは、オブジェクトの有効期間をまったくモデル化しないため、これを考慮できません。

std::weak_ptrスマートポインタは、プレーン、参照に似たエンコードの所有権の意味を行いますが、参照されたオブジェクトを介して管理されている必要がありshared_ptr、つまりは、参照カウントです。これはゼロコストの抽象化ではありません。

C ++にはconstシステムがありますが、これはオブジェクトを変更できるかどうかを追跡するのではなく、その特定の参照を通じてオブジェクトを変更できるかどうかを追跡します。それは「大胆不敵な並行性」に十分な保証を提供しません。対照的に、Rustは、唯一の参照であるアクティブな可変参照(「このオブジェクトを変更できる唯一のユーザー」)が存在し、不変の参照がある場合、そのオブジェクトへのすべての参照が不変であることを保証します(「オブジェクトから読み取ることはできますが、変更することはできません」)。

C ++では、mutexを使用したスマートポインターを介したオブジェクトへのアクセスを保護したくなるかもしれません。しかし、上記で説明したように、参照を取得すると、予想される存続期間を回避できます。したがって、このようなスマートポインターは、管理対象オブジェクトへの単一のアクセスポイントであることを保証できません。ほとんどのプログラマーは自分自身を妨害したくないので、そのようなスキームは実際に機能するかもしれませんが、型システムの観点からはこれはまだ完全に不健全です。

スマートポインターの一般的な問題は、それらがコア言語の上にあるライブラリであるということです。コア言語機能のセットにより、これらのスマートポインターが有効になります。たとえば、std::unique_ptrムーブコンストラクターが必要です。ただし、コア言語内の欠陥を修正することはできません。関数を呼び出すときに暗黙的に参照を作成し、参照をダングリングする機能は、コアC ++言語が不適切であることを意味します。可変参照を単一の参照に制限できないということは、C ++があらゆる種類の並行性を持つ競合状態に対する安全性を保証できないことを意味します。

もちろん、多くの点で、C ++とRustは、特に静的に決定されたオブジェクトライフタイムの概念に関して、嫌いというよりも似ています。しかし、正しいC ++プログラムを書くことは可能ですが(プログラマーが間違いを犯さなければ)、Rust は議論されたプロパティに関する正確さを保証します。


C ++がコア言語の所有権を追跡しないという問題がある場合、メタプログラミングを介してその機能を実装することは可能でしょうか?つまり、(1)同じクラスのスマートポインターのみを使用するオブジェクトのみを指すように強制し、(2)テンプレートを介して所有権を追跡することにより、メモリセーフな新しいスマートポインタークラスを作成することを意味します
Elliot Gorokhovsky

2
@ElliotGorokhovskyいいえ、テンプレートは参照などのコア言語機能を無効にできないためです。スマートポインターを使用すると、参照を取得することが難しくなりますが、その時点で言語と戦っています。ほとんどの標準ライブラリ関数には参照が必要です。言語には有効期間の具体化された概念がないため、テンプレートを使用して参照の有効期間をチェックすることもできません。
アモン

わかりました、ありがとう
エリオット・ゴロホフスキー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.