在堆上存放unique_ptr的最简单方法是什么?

时间:2019-01-22 04:09:05

标签: c++ unique-ptr

长时间使用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()中崩溃了,但是我无法确定它是否崩溃了,因为我做错了什么,或者我正在使用的库中有一些错误(相对较新且越野车)。

感谢任何“指针”。

1 个答案:

答案 0 :(得分:5)

可以简化。

由于您必须与Java的生命周期管理集成,因此unique_ptr不会给您任何帮助。您最好直接管理T对象的生存期,而不要为其管理包装器(当然,对于FooHolder的包装器,当然也不能管理unique_ptr的包装器) -太多包裹了。

只需在T上调用release()即可获得unique_ptr<T> -d,在使用完之后,它就必须是T*-d。