首页 > 解决方案 > 在堆上存储 unique_ptr 的最简单方法是什么?

问题描述

长时间使用 Java,第一次使用 C++。

我正在编写一个包装现有 C++ API 的 Java 类,看起来像这样:

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

感谢任何“指针”。

标签: c++unique-ptr

解决方案


它可以简化。

由于您必须与 Java 的生命周期管理集成,这对unique_ptr您没有任何好处。您还不如直接管理对象的生命周期T,而不是它的包装器(当然也不是FooHolder包装器的unique_ptr包装器T- 包装太多了)。

当你完成它时,只需调用release()unique_ptr<T>来获得一个T*需要-d 的东西。delete


推荐阅读