Constructing an object crashes the jvm because the constructor is not found. The signature is correct and the constructor exists.
This is my new object code:
JavaObject(jclass klass, const char *signature, ...) {
std::cout << "constructing" << std::endl;
va_list arg;
va_start(arg, signature);
jmethodID constructor = client->env->GetMethodID(klass, "<init>", signature);
jobject newObject = client->env->NewObjectV(klass, constructor, arg);
this->object = &newObject;
va_end(arg);
}
And then:
// javaClass->getClass() is java.lang.String
String(jcharArray v1) : JavaObject(javaClass->getClass(), "([C)V", v1) {}
edit: my class is java.lang.String
. It has the constructor String(char[])
. Running javap -s
gives me the signature.
>Solution :
You can never directly access the va_list
value. You must call va_arg
on it to get the arguments. va_list
does not contain the first argument; it contains an unspecified type which can access the first argument by means of va_arg
.
jobject newObject = client->env->NewObjectV(klass, constructor, va_arg(arg, ExpectedType));
But this is all academic, because we’re in C++ in 2023, not C in 1991. There’s no compelling reason to use va_list
at all anymore; it’s just a less type-safe version of variadic parameter packs. Your signature should look something like
template <typename... Ts>
JavaObject(jclass klass, const char *signature, const Ts&... args)
To use args
(which is now type-safe), you can expand it in another argument list as
client->env->NewObjectV(klass, constructor, args...);
You can use it in a std::tuple
or other type that expects parameter packs, to perform runtime operations on the pack as a single data structure.
auto my_args = std::make_tuple(args...);
You can’t invoke undefined behavior by using parameter packs with the wrong types, as you’ll just get a compiler error rather than the runtime just dying in exciting ways.