Ruby 用の C++ 拡張機能を作成しているときに苦労している 1 つの問題は、ユーザーがばかげたことをしても本当に安全にすることです。その場合、例外が発生するはずですが、SegFault は発生しません。具体的な問題は次のとおりです。私の C++ クラスには自明でないコンストラクタがあります。次に、Rice API を使用して C++ クラスをラップします。ユーザーが Ruby コードで initialize() を再定義すると、Rice によって作成された initialize() 関数が上書きされ、オブジェクトは割り当ても初期化もされません。おもちゃの例としては、次のようなものがあります。
class Person {
public:
Person(const string& name): m_name (name) {}
const string& name() const { return m_name; }
private:
string m_name;
}
次に、次のような Ruby クラスを作成します。
define_class<Person>("Person")
.define_constructor(Constructor<Person, const string&>(), Arg("name"))
.define_method("name", &Person::name);
次に、次の Ruby コードで Segfault が発生します
require 'MyExtension'
class Person
def initialize
end
end
p = Person.new
puts p.name
Ruby で初期化関数を何らかの方法で上書きすることを禁止するか、オブジェクトが正しく割り当てられている場合は C++ でチェックし、そうでない場合は例外をスローします。
Ruby C API を直接使用したことがありますが、それは簡単でした。ヌル ポインターと、allocate() 関数で false に設定されたフラグで構成されるダミー オブジェクトを割り当てました。また、initialize メソッドで、実際のオブジェクトを割り当てて、フラグを true に設定しました。すべてのメソッドで、そのフラグをチェックし、false の場合は例外を発生させました。ただし、Ruby C API を使用して多くのばかげた反復コードを作成しました。まず、C からアクセスできるように C++ クラスをラップし、次に Ruby 型をラップおよびアンラップする必要がありました。さらに、この愚かなフラグをチェックする必要がありましたすべての方法を試してみたので、Rice に移行しました。これは本当に素晴らしいことで、とてもうれしいです。
ただし、Rice では、プログラマーは、rice によって作成された initialize() 関数で呼び出されるコンストラクターしか提供できず、allocate() 関数は事前定義されており、何もしません。これを変更したり、「公式の」方法で独自の割り当て関数を提供したりする簡単な方法はないと思います。もちろん、C API を使用してアロケート関数を定義することもできたので、C API と Rice を何とか混ぜてみましたが、非常に厄介になり、奇妙な SegFaults が発生し、非常に醜いので、そのアイデアを放棄しました。 .
ここにライスの経験がある人はいますか、それともこれを安全にする方法を知っている人はいますか?