5

好的,首先我对 C++ 很陌生,如果我的理解很差,我深表歉意。我会尽力解释自己。我所拥有的是我正在使用一个返回 a 的库函数,std::shared_ptr<SomeObject>然后我有一个不同的库函数,它接受一个原始指针参数(更具体地说是 node-addon-apiNapi::External<T>::New(Napi::Env env, T *data)静态函数)。我想Napi::External使用我的 std::shared_ptr 创建一个对象。我目前正在做的是这样的:

{
    // ...
    std::shared_ptr<SomeObject> pSomeObject = something.CreateSomeObject();
    auto ext = Napi::External<SomeObject>::New(info.Env(), pSomeObject.get());
    auto instance = MyNapiObjectWrapper::Create({ ext });
    return instance;
}

但我担心这会遇到内存问题。我的 pSomeObject 只存在于当前范围内,所以我想在返回之后应该发生什么,它的引用计数将下降到 0 并且它指向的 SomeObject 实例将被销毁,因此我会遇到我返回的实例的问题使用这个对象。但是,我已经能够从我的实例中运行此代码并在 SomeObject 上调用函数,所以我想我的理解可能是错误的。

我的问题是当给定一个共享指针但由于其他第三方库的要求我需要处理一个原始指针时我应该怎么做?向我提出的一个选项是制作对象的深层副本并创建指向该对象的指针

如果我对此的任何理解是错误的,请纠正我,因为我说我对 C++ 很陌生。

==============================

编辑:

因此,我的原始帖子信息中缺少有关所有权以及该块到底是什么的信息。该块是我对实例的实现的实例方法Napi::ObjectWrap。此实例方法需要返回一个Napi::Object可供 node.js 中的调用者使用的对象。我正在使用Napi::External,因为我需要在创建 I 返回时将子类型传递Napi::Value给构造函数,并且我需要在构造函数中提取的外部包装对象,如下所示:NewNapi:ObjectSomeObjectMyNapiObjectWrapper

class MyNapiObjectWrapper
{
private:
    SomeObject* someObject;
    static Napi::FunctionReference constructor; // ignore for now
public:
    static void Init(Napi::Env env) {...}
    MyNapiObjectWrapper(const CallbackInfo& info)
    {
        Napi::Env env = info.Env();
        Napi::HandleScope scope(env);

        // My original code to match the above example
        this->someObject = info[0].As<const Napi::External<SomeObject>>().Data();
    }

    DoSomething()
    {
        this->someObject->DoSomething();
    }
}

从那以后我意识到我可以在创建外部时传递共享指针的地址并按如下方式使用它

// modified first sample
{{
    // ...
    std::shared_ptr<SomeObject> pSomeObject = something.CreateSomeObject();
    auto ext = Napi::External<SomeObject>::New(info.Env(), &pSomeObject);
    auto instance = MyNapiObjectWrapper::Create({ ext });
    return instance;
}

// modified second sample
class MyNapiObjectWrapper
{
private:
    std::shared_ptr<SomeObject> someObject;
    static Napi::FunctionReference constructor; // ignore for now
public:
    static void Init(Napi::Env env) {...}
    MyNapiObjectWrapper(const CallbackInfo& info)
    {
        Napi::Env env = info.Env();
        Napi::HandleScope scope(env);

        // My original code to match the above example
        this->someObject = 
            *info[0].As<const Napi::External<std::shared_ptr<SomeObject>>>().Data();
    }

    DoSomething()
    {
        this->someObject->DoSomething();
    }
}

所以现在我传递一个指向 shared_ptr 的指针来创建我的Napi::External,我现在的问题是这样可以吗?就像我在开始时所说的那样,我是 C++ 新手,但这似乎有点异味。但是我通过一些调试对其进行了测试,并且可以看到引用计数上升,所以我想我很清楚???

4

1 回答 1

3

这里是文档的重要部分:

Napi::External 模板类实现了使用任意 C++ 数据创建 Napi::Value 对象的能力。管理任意 C++ 数据的内存是用户的责任

所以需要确保传递data给toNapi::External Napi::External::New的对象退出,直到Napi::External<T>对象被破坏。

因此,您显示的代码不正确。

您可以做的是将Finalize回调传递给New函数:

static Napi::External Napi::External::New(napi_env env,
                    T* data,
                    Finalizer finalizeCallback);

并使用 lambda 函数 as Finalize,该 lambda 可以通过捕获将副本保存到共享指针,从而使共享指针保持活动状态,直到调用 finalize。

std::shared_ptr<SomeObject> pSomeObject = something.CreateSomeObject();
auto ext = Napi::External<SomeObject>::New(
                  info.Env(), 
                  pSomeObject.get(),
                  [pSomeObject](Env /*env*/, SomeObject* data) {});
于 2019-11-09T14:27:06.537 回答