Reputation: 523
I'm working on a Android NDK-based code and I don't get how "long" is the lifespan of my string literals. My program is a C++ game which interacts with the Android Java-side from time to time – like uploading data on servers, connecting to Facebook, etc.
In a downcall from Java to (native) C++, I use different ways to convert jstring
to const char*
, and I realized that some work but another doesn't. And I don't understand why.
E.g.: in a JNI downcall, where toCall(const char*)
is a regular C++ function which is defined elsewhere.
JNIEXPORT void JNICALL Java_com_alpha_beta_Gamma_onDelta(JNIEnv *env, jclass, jstring jstr) {
// #1
const char* cVar = jnu::ToString(jstr).c_str();
toCall(cVar);
// #2
std::string strVar = jnu::ToString(jstr);
toCall(strVar.c_str())
// #3
toCall(jnu::ToString(jstr).c_str());
// #4
std::string strVara;
jnu::SetString(jstr, strVara);
toCall(strVara.c_str());
}
And the jnu
functions are:
std::string jnu::ToString(JNIEnv *env, jstring jstr) {
if (jstr) {
const char *cstr = env->GetStringUTFChars(jstr, NULL);
std::string str = cstr;
env->ReleaseStringUTFChars(jstr, cstr);
return str;
}
return std::string();
}
std::string& jnu::SetString(JNIEnv* env, jstring jstr, std::string& output) {
if (jstr) {
const char *cstr = env->GetStringUTFChars(jstr, NULL);
output = cstr;
env->ReleaseStringUTFChars(jstr, cstr);
}
return output;
}
Cases #2
, #3
and #4
work just fine, whereas #1
just send plain garbage to the function to call.
Maybe it's C++ 101 but I don't get why my #1 case is buggy. Someone please give me any clue?
Thanks!
Upvotes: 0
Views: 405
Reputation: 30579
The char
array pointed to by the pointer returned by std::string::c_str
is owned by the std::string
instance. That means that when the string
that you called c_str
on goes out of scope the data pointed to is deleted.
This is what happens in case #1. The return value of jnu::ToString
(or any other temporary) goes out of scope at the end of the expression, so as soon as you initialize cVar
the data it points to gets deleted and you have a dangling pointer. Any attempt to dereference a dangling pointer will result in undefined behavior.
In case #2 the string
returned by jnu::ToString
gets copied to strVar
(or maybe moved, or maybe Return Value Optimization kicks in and no temporary ever actually gets created; it doesn't really matter). The data pointed to by the pointer returned by strVar.c_str()
will continue to exist until strVar
goes out of scope or needs to reallocate its storage.
In case #3 the temporary string
returned by jnu::ToString
will continue to exist through the full expression, so it survives through the call to toCall
.
Case #4 is similar to #2 except for how jnu::SetString
fills strVara
.
Upvotes: 2