Шаблоны JNI C ++ для приобретения / выпуска ресурсов

Какой набор шаблонов или библиотека рекомендуется использовать для получения / освобождения ресурсов 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.

3

Решение

Ключевое слово здесь 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
}
3

Другие решения

Ты можешь использовать 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));
8

По вопросам рекламы [email protected]