Какой набор шаблонов или библиотека рекомендуется использовать для получения / освобождения ресурсов JNI из кода C ++?
«Плохой» пример:
//C++ code
extern "C"JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
const char *nativeString = env->GetStringUTFChars(javaString, 0);
//Do something with the nativeString
//DON'T FORGET THIS LINE!!!
env->ReleaseStringUTFChars(javaString, nativeString);
}
Очевидно, что все используют набор шаблонов, а не код выше.
Для jstring он вызывает GetStringUTFChars для получения ресурса и ReleaseStringUTFChars для освобождения, когда объект выходит из области видимости.
Должен быть чем-то похожим на шаблон auto_ptr, но с учетом JNI, например, для вызова GetStringUTFChars / ReleaseStringUTFChars для jstring.
Ключевое слово здесь RAII:
class jni_string {
public:
jni_string(JNIEnv *env, jstring javaString)
: env_(env), javaString_(javaString)
{ nativeString_ = env_->GetStringUTFChars(javaString_, 0); }
~jni_string() { env_->ReleaseStringUTFChars(javaString_, nativeString_); }
operator const char *() const { return nativeString_; }
private:
jni_string(const jni_string &x);
jni_string &operator=(const jni_string &x);
JNIEnv *env_;
jstring javaString_;
const char *nativeString_;
};
Использование будет:
//C++ code
extern "C"JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string nativeString(env, javaString);
//Do something with the nativeString
}
Ты можешь использовать std::unique_ptr
в C ++ 11, который позволяет вам самостоятельно установить средство удаления:
#include <memory>
#include <functional>
typedef std::unique_ptr<char const[], std::function<void(char const*)>> jni_string_ptr;
// the "std::function" is needed to store any callable†
extern "C"JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string_ptr nativeString(env->GetStringUTFChars(javaString, 0),
[=](char const* p) mutable{ env->ReleaseStringUTFChars(javaString, p); });
// lambda as the deleter
// mutable needed if "ReleaseStringUTFChars" is a non-const method
//Do something with the nativeString
// nativeString automatically calls the passed deleter
}
Если вы застряли в C ++ 03 и не имеете доступа к std::unique_ptr
, boost::shared_array
обеспечивает .. жизнеспособный альтернатива.
#include <boost/shared_ptr.hpp>
typedef boost::shared_array<char const*> jni_string_ptr;
struct jni_string_deleter{
jni_string_deleter(JNIEnv* e, jstring js)
: _env(e), _java_string(js) {}
void operator()(char const* p) const{
_env->ReleaseStringUTFChars(_java_string, p);
}
private:
JNIEnv* _env;
jstring _java_string;
};
extern "C"JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string_ptr nativeString(env->GetStringUTFChars(javaString, 0),
jni_string_deleter(env, javaString));
//Do something with the nativeString
// nativeString automatically calls the passed deleter
}
† Вы также можете использовать определенный тип дельтеров здесь, как с shared_array
Например, чтобы избежать затрат на стирание типа std::function
:
struct jni_string_deleter{
jni_string_deleter(JNIEnv* e, jstring js)
: _env(e), _java_string(js) {}
void operator()(char const* p) const{
_env->ReleaseStringUTFChars(_java_string, p);
}
private:
JNIEnv* _env;
jstring _java_string;
};
typedef std::unique_ptr<char const[], jni_string_deleter> jni_string_ptr;
// create
jni_string_ptr(env->get_the_chars(), jni_string_deleter(env, javaString));