問題タブ [pybind11]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - Pybind - 不思議なことに繰り返されるテンプレート
私は次のクラス構造を持っています (私の実際の実装の単純化された例):
その後
これは、この質問PyBind11 Template Class of Many Typesへの回答に大まかに基づいています。ただし、エラーは次のとおりです。
C2783 'pybind11::class_> &pybind11::class_>::def(const char *,Func &&,const Extra &...)': 'Func' のテンプレート引数を推測できませんでした ...\source.cpp 10
C2672 'pybind11::class_>::def': 一致するオーバーロードされた関数が見つかりません ...\source.cpp 12
ジェネリック関数が後で渡されるtemplate <class FuncType>
ため、どこにも定義できない秒に関係しているようです。func
この問題を回避する方法はありますか?
c++ - ノードベースのツリー構造の Python バインディング
環境
私は、 XML DOMと非常によく似たセマンティクスと機能を備えたノードベースのツリー構造としてデータが編成される2D アニメーション システムを開発していますが、既存の XML 実装を使用するほどには似ていません。わかりやすくするために、単純化して、データ構造が次の疑似コードによって概念的に定義されていると仮定しましょう。
最新の C++ の最先端のガイドライン ( Core Guidelines、Herb Sutter talkなど) に従うと、所有ハンドルにはスマート ポインターを使用し、非所有ハンドルには raw ポインターを使用するのが適切な選択です。所有権は一意であるため、std::unique_ptr
意味があります。
この API は、クライアント コードが何をしているかを知っていることを前提としています。を使用する場合と同様にlist::iterator
、クライアントはドキュメントを読んでどの操作がノードを無効にするかを知る必要がありNode*
ます。私は C++ クライアント向けのこのアプローチに賛同しています。これは慣用的な C++ であり、パフォーマンスに対して支払う代償だと思います。
ただし、Python クライアントにより多くの安全性を提供する必要があります。アニメーション ソフトウェアは、組み込みの Python コンソールを備えた C++ GUI プログラムです。つまり、多くの Python クライアントは、プログラミング経験がほとんどなく、ほとんどがチュートリアルからコードをコピーして貼り付け、ニーズに合わせて調整するアーティストであることが期待されます。さらに悪いことに、このような信頼性の低いテストされていない Python コードは、ユーザーが潜在的に貴重な保存されていないデータを使用して長時間の対話セッションを行っている間に実行される可能性があります。Python クライアントが期限切れのノードを使用しようとしても、ソフトウェアがクラッシュすることは絶対にありません。予想される動作は、次のようなものです。
質問
期待される動作を得るために、pybind11 を使用してこの C++ API をどのようにラップしますか?
必要に応じて、C++ API をどのように変更して、そのような動作を許可したり、ラッパー コードをより読みやすく、慣用的にしたりしますか?
すでに試したことや検討したこと
素朴な as ラッピングは機能しません。Pythonclass_<Node>(m, "Node")
インスタンスは、ノードがまだ有効かどうかを認識できません。基本的に、Node*
viaを返すと二重削除になり、 viaまたはのtake_ownership
いずれかを返すと、未定義の動作 (読み取り、セグメンテーション違反) が発生します。reference
reference_internal
PyNode
そのため、トランポリン クラスが他の手段 (たとえば、 などのコールバックの登録) を介してノードの有効性を追跡するかNode::onAboutToDie()
、参照カウント スマート ポインターを使用するように C++ 所有権モデルを変更する必要があります。
私が良い選択肢であると信じていたのは、C++ コードをshared_ptr
の代わりに使用するように変更することでしunique_ptr
た。Node
から派生し、ボンネットの下にカスタム ホルダーが格納されている場所enable_shared_from_this
としてラップします。ノードは から派生するため、所有者は生のポインタを に変換するコンストラクタを持つことができます。簡単に言えば、これは共有ポインターの参照カウント機能を利用して、所有権を共有するのではなく (所有権は依然として一意です)、Python 側で弱い参照を使用できるようにするだけです。class_<Node, PyWeakPtr<Node>>(m, "Node")
PyWeakPtr
weak_ptr
enable_shared_from_this
PyWeakPtr(T*)
weak_ptr
expired()
すべてのアクセスの前に、有効期限が切れた場合にキャッチ可能な例外をスローします。ただし、これまでのところ、私のさまざまな試みは失敗しました。期待される動作を得ることができなかったか、コンパイルすることさえできなかったなどです。
これに基づくより明白な解決策は、カスタムの holder の代わりにshared_ptr
使用することですが、Python 変数がそれらを指している限り、ノードの寿命を人為的に延長するため、どちらも機能しません。これはリークだと思います。ノードは共有されるべきではなく、ユーザーが UI でノードを削除すると、ノードは削除され、デストラクタがすぐに呼び出されます。セマンティクスは、Python で「セマンティックに削除された」ノードにアクセスすると、(C++ プログラムをクラッシュさせることなく) Python エラーが発生し、有効なノードとして黙ってマスカレードするのではありません。class_<Node, std::shared_ptr<Node>>(m, "Node")
PyWeakPtr
役立つ場合は、これらの試みのいくつかを clean/make_minimal/etc するのに時間をかけるかもしれませんが、今のところ、簡潔にするために質問をそのままにしておきます。ここにいる専門家の中には、アプローチ全体が理にかなっているなど:)
QDomDocument
Qtや Pixar のUniversal Scene Descriptionなど、同様の問題を解決する多くの既存のソフトウェアは、C++ API でも参照カウントされた弱参照 (多かれ少なかれ内部に隠されている) を使用する傾向があり、C++ と Python のクライアントの間違いから完全に保護されていることに注意してください。私はこのアプローチにもオープンですが、理想的には、C++ で所有していない生のポインターを単純に使用するという一般的なガイドラインに固執することを好むと思います。