2

通常の std::map を使用して、jobject を C++ オブジェクトにマップします。このアプローチの問題は、他のタイプの参照では失敗する可能性があることです。たとえば、グローバル参照は、同じオブジェクトを参照していても、実際には通常のローカル参照とは異なるポインターです。2 つの参照が同じオブジェクトを参照している場合の正しい比較方法は次のとおりです。

env->IsSameObject(jobj1, jobj2);

だから、私の質問は次のとおりです: jobject を c++ オブジェクトにマップする正しい方法は何ですか? operator== をオーバーロードして IsSameObject を呼び出すいくつかの c++ クラスに jobject をラップするという明らかな応答は、私が探している応答ではありません。比較操作ごとに JVM とネイティブ c/c++ の間を行き来せずにそれを行う方法があるかどうか知りたいです。

編集:グローバル参照は jni グローバル参照であり、c++ 参照とは関係ありません。

EDIT2:このコードの問題を明確にしたいと思います:

std::map<jobject, void *> jobjs;
jobject obj1, obj2;
... some code that sets these obj1 and obj2 to some Java objects.

jobjs[obj1] = new CppPeer;
CppPeer * = jobjs[obj1]; //OK...
if(objs.find(obj2) == objs.end()){
   assert(obj2 != obj1);
   //Here's the problem: here a new c++ CppPeer
   //created for obj2, but the problem is that 
   //even if obj1 != ob2 it doesn't mean that
   //they actually reference different java objects
   //On the next line error might happen
   jobjs[obj2] = new CppPeer; //maybe not OK here...
}

IsSameObject のもう 1 つの問題は、物事がかなり厄介で厄介になることです。JVMへのポインタを保持する必要があるだけでなく、ジョブジェクトを比較する必要があるときはいつでも、スレッドなどをアタッチしてJNIEnvへのポインタを取得し、ジョブジェクトをチェックできるようにする必要があります

EDIT3: Androidのドキュメントによると、2つの参照が等しい場合、それらが同じオブジェクトを参照していると仮定することさえできないことに注意してください。それがどのように可能かはわかりませんが、Android の JNI ヒント ページの一部があります。

この結果の 1 つは、オブジェクト参照がネイティブ コードで一定または一意であると想定してはならないということです。オブジェクトを表す 32 ビット値は、メソッドの呼び出しごとに異なる場合があり、2 つの異なるオブジェクトが連続した呼び出しで同じ 32 ビット値を持つ可能性があります。jobject 値をキーとして使用しないでください

4

1 に答える 1

1

免責事項:においがします。

Android では、ポインタとjintは同じサイズです。Java クラスに int フィールドを追加して、ネイティブ conterpart へのポインターを格納することを検討してください。JNI メソッドの場合は、型キャストしてポインターに戻します。

少し安全にするために、データ型の一致に対して静的アサートを行います。

{char a[sizeof(void*) == sizeof(jint) ? 1 : -1]};

そうでないシステムでコンパイルすると、コンパイル エラーが発生します。

少し臭いを抑えるには、mapint からオブジェクトへの static/global を使用し、ID ジェネレーターを使用し、オブジェクト ポインターの代わりに、Java オブジェクト内に比較的一意の (プロセスの有効期間内で) オブジェクト ID を格納します。

于 2012-10-24T01:57:19.310 に答える