11 Unstar Star 28 Fork 21

OpenHarmony / utils_native_liteApache-2.0

【优化】js/built目录下的资源管理RAII化讨论

任务
待办的
Gymee  Opened this issue

该问题是怎么引起的?

纯属讨论性质的话题

重现步骤

不涉及

报错信息

不涉及

如有理解不对的地方,望指正

原始代码
void ExecuteGetInfo(void* data)
{
    FuncParams* params = reinterpret_cast<FuncParams *>(data);
    if (params == nullptr) {
        return;
    }
    JSIValue args = params->args;
    JSIValue thisVal = params->thisVal;
    char* brand = GetBrand();
    if (brand == nullptr) {
        NativeapiCommon::FailCallBack(args, thisVal, ERROR_CODE_GENERAL);
        JSI::ReleaseValueList(args, thisVal, ARGS_END);
        delete params;
        return;
    }
    char* manufacture = GetManufacture();
    if (manufacture == nullptr) {
        free(brand);
        NativeapiCommon::FailCallBack(args, thisVal, ERROR_CODE_GENERAL);
        JSI::ReleaseValueList(args, thisVal, ARGS_END);
        delete params;
        return;
    }
    char* model = GetProductModel();
    if (model == nullptr) {
        free(brand);
        free(manufacture);
        NativeapiCommon::FailCallBack(args, thisVal, ERROR_CODE_GENERAL);
        JSI::ReleaseValueList(args, thisVal, ARGS_END);
        delete params;
        return;
    }
    JSIValue result = JSI::CreateObject();
    JSI::SetStringProperty(result, "brand", brand);
    JSI::SetStringProperty(result, "manufacturer", manufacture);
    JSI::SetStringProperty(result, "model", model);
    JSI::SetStringProperty(result, "product", model);
    Screen &screen = Screen::GetInstance();
    JSI::SetNumberProperty(result, "windowWidth", (double)screen.GetWidth());
    JSI::SetNumberProperty(result, "windowHeight", (double)screen.GetHeight());
    free(brand);
    free(manufacture);
    free(model);
    NativeapiCommon::SuccessCallBack(thisVal, args, result);
    JSI::ReleaseValueList(args, thisVal, result, ARGS_END);
    delete params;
    params = nullptr;
}

上述代码虽然是c++代码,但是感觉很c,资源释放都要手动管理,每次分支返回都要进行释放,产生了很多重复代码,主体的逻辑也淹没在资源释放的代码中

修改后的代码
void ExecuteGetInfo(void* data)
{
    if (data == nullptr) {
        return;
    }
    FuncParamsUniquePtr params(reinterpret_cast<FuncParams *>(data), &JSIDeleters::FuncParamsDeleter); // 使用智能指针管理
    RawCharArrayUniquePtr brand(GetBrand(), &JSIDeleters::RawCharArrayDeleter); // 使用智能指针管理
    if (brand == nullptr) {
        NativeapiCommon::FailCallBack(params->args, params->thisVal, ERROR_CODE_GENERAL);
        return;
    }
    RawCharArrayUniquePtr manufacture(GetManufacture(), &JSIDeleters::RawCharArrayDeleter); // 使用智能指针管理
    if (manufacture == nullptr) {
        NativeapiCommon::FailCallBack(params->args, params->thisVal, ERROR_CODE_GENERAL);
        return;
    }
    RawCharArrayUniquePtr model(GetProductModel(), &JSIDeleters::RawCharArrayDeleter); // 使用智能指针管理
    if (model == nullptr) {
        NativeapiCommon::FailCallBack(params->args, params->thisVal, ERROR_CODE_GENERAL);
        return;
    }
    JSIValueGeneralRAII result(JSI::CreateObject()); // 使用RAII包装类进行包装
    JSI::SetStringProperty(result.raw, "brand", brand.get());
    JSI::SetStringProperty(result.raw, "manufacturer", manufacture.get());
    JSI::SetStringProperty(result.raw, "model", model.get());
    JSI::SetStringProperty(result.raw, "product", model.get());
    Screen &screen = Screen::GetInstance();
    JSI::SetNumberProperty(result.raw, "windowWidth", (double)screen.GetWidth());
    JSI::SetNumberProperty(result.raw, "windowHeight", (double)screen.GetHeight());
    NativeapiCommon::SuccessCallBack(params->thisVal, params->args, result.raw);
}

原代码中的指针,使用智能指针进行管理,其它类型使用一个RAII包装类进行包装,这样资源释放就不用显示去操作,逻辑也更清晰,后面新增代码也不用担心一不下心就资源泄漏了。

另外,如果在将下面代码,使用一个RETURN_IF_NULL_WITH_CALLBACK(xxx == nullptr)进行替换的话,代码就会更简洁

    if (model == nullptr) {
        NativeapiCommon::FailCallBack(params->args, params->thisVal, ERROR_CODE_GENERAL);
        return;
    }

【修改的好处】
整个js/builtin目录下,存在大量类似的,使用上述改造会使得代码更简洁,代码也更c++,后续代码修改也不容易出错。

相关修改 (新增)

nativapi_common.h

struct JSIDeleters {
    static void FuncParamsDeleter(FuncParams* params);
    static void RawCharArrayDeleter(char* str);
};

struct JSIStringPropertyRAII {
    JSIStringPropertyRAII(JSIValue object, const char* propName)
    {
        raw = JSI::GetStringProperty(object, propName);
    }

    ~JSIStringPropertyRAII()
    {
        JSI::ReleaseString(raw);
    }

    char* raw {nullptr};
};

struct JSIValueGeneralRAII {
    JSIValueGeneralRAII(JSIValue object)
    {
        raw = object;
    }

    ~JSIValueGeneralRAII()
    {
        JSI::ReleaseValue(raw);
    }

    JSIValue raw {nullptr};
};

using FuncParamsUniquePtr = std::unique_ptr<FuncParams, decltype(&JSIDeleters::FuncParamsDeleter)>;
using RawCharArrayUniquePtr = std::unique_ptr<char, decltype(&JSIDeleters::RawCharArrayDeleter)>;

nativeapi_common.cpp

void JSIDeleters::FuncParamsDeleter(FuncParams* params) // 释放params
 {
    if (params == nullptr) {
        return;
    }
    JSI::ReleaseValueList(params->args, params->thisVal, ARGS_END);
    delete params;
};

void JSIDeleters::RawCharArrayDeleter(char* str) // 释放char*
{
    if (str == nullptr) {
        return;
    }
    free(str);
}
Attachments
total 1 participants

Comments (0)

Sign in to comment

Assignees
Labels
Not set
Projects
Milestones
Branches
Planed to start
Not set
Planed to end
Not set
Top level
Priority
1
https://git.oschina.net/openharmony/utils_native_lite.git
git@git.oschina.net:openharmony/utils_native_lite.git
openharmony
utils_native_lite
utils_native_lite

Search