Получение необработанного указателя из shared_ptr для передачи его в функцию, которая требует raw - PullRequest
5 голосов
/ 09 ноября 2019

Хорошо, во-первых, я очень плохо знаком с C ++, поэтому извиняюсь, если мое понимание плохое. Я постараюсь объяснить, как могу. Я использую библиотечную функцию, которая возвращает std::shared_ptr<SomeObject>, затем у меня есть другая библиотечная функция, которая принимает необработанный аргумент-указатель (более конкретно, статическая функция node-addon-api Napi::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, так как мне нужно передать подтип Napi::Value функции конструктора New при создании возвращаемого мной Napi:Object, и мне нужен обернутый объект SomeObject во внешнем объекте, который я извлекаю вМой конструктор MyNapiObjectWrapper выглядит так:

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 ++, но это похоже на запах. Однако я проверил это с некоторой отладкой и увидел, что счетчик ссылок увеличился, так что я думаю, что я в чистом виде ???

1 Ответ

3 голосов
/ 09 ноября 2019

Здесь важная часть документации :

. Шаблонный класс Napi :: External реализует возможность создания объекта Napi :: Value с произвольными данными C ++. Пользователь несет ответственность за управление памятью для произвольных данных C ++ .

Поэтому необходимо убедиться, что объект, переданный data в Napi::External Napi::External::New, завершится до тех пор, покаNapi::External<T> объект разрушен.

Таким образом, код, который вы показали, неверен.

Что вы могли бы сделать, это передать Finalize обратный вызов функции New:

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

И использовать лямбда-функцию в качестве Finalize, чтобы лямбда могла хранить копию через захват до общего указателя, позволяя поддерживать общий указатель живым, пока не будет вызван финализатор.

std::shared_ptr<SomeObject> pSomeObject = something.CreateSomeObject();
auto ext = Napi::External<SomeObject>::New(
                  info.Env(), 
                  pSomeObject.get(),
                  [pSomeObject](Env /*env*/, SomeObject* data) {});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...