长时间使用Java,第一次使用C ++。
我正在编写一个Java类,该类包装了一个现有的C ++ API,看起来像这样:
public class Foo implements Closeable {
private long handle;
public Foo(File file) {
this.handle = Foo.openFile(file.toString());
}
// other methods go here...
public void close() {
Foo.closeFile(this.handle);
this.handle = 0;
}
private static native long openFile(String file);
private static native void closeFile(long handle);
}
我们会将指向本地C ++对象的指针填充到handle
字段中。
问题是C ++库没有给我指针,而是给了我unique_ptr<Foo>
。因此,必须将其移至openFile()
中的堆上(这样它才不会超出范围),然后在closeFile()
中销毁。
我无法使它正常工作,并且不确定我是否做得正确。在C ++中正确执行此操作的最简单/最干净的方法是什么?
这是我目前正在做的事情:
// This holds a unique_ptr<T>, typically on the heap, until no longer needed
template <class T>
class PointerHolder {
public:
PointerHolder(unique_ptr<T> ptr) {
this->ptr = std::move(ptr);
}
T * get() const {
return this->ptr.get();
}
private:
unique_ptr<T> ptr;
};
// Holder for a Foo
typedef PointerHolder<Foo> FooHolder;
jlong JNICALL
Java_Foo_openFile(JNIEnv *jenv, jclass jcls, jstring file)
{
...
// Get smart pointer to native object from provided C++ library
unique_ptr<Foo> ptr = ...
// Save pointer on the heap until closeFile() is invoked sometime later
const FooHolder *const holder = new FooHolder(std::move(ptr));
// Return pointer encoded as a Java long
return reinterpret_cast<jlong>(holder);
}
void JNICALL
Java_Foo_closeFile(JNIEnv *jenv, jclass jcls, jlong handle)
{
// Delete pointer holder, and by extension, storage object
delete reinterpret_cast<FooHolder *>(handle); // CRASH HERE
}
这是正确的吗?如果是这样,可以简化吗?
无论如何,现在程序在closeFile()
中崩溃了,但是我无法确定它是否崩溃了,因为我做错了什么,或者我正在使用的库中有一些错误(相对较新且越野车)。
感谢任何“指针”。
答案 0 :(得分:5)
可以简化。
由于您必须与Java的生命周期管理集成,因此unique_ptr
不会给您任何帮助。您最好直接管理T
对象的生存期,而不要为其管理包装器(当然,对于FooHolder
的包装器,当然也不能管理unique_ptr
的包装器) -太多包裹了。
只需在T
上调用release()
即可获得unique_ptr<T>
-d,在使用完之后,它就必须是T*
-d。