在 oop 应用程序 c++ 中使用 V8 引擎

Use V8 engine in oop application c++

我想在 C++ 中基于 oop 的应用程序中使用 v8,但是我的代码中的 v8 对象范围存在一些问题,当我在一个函数中编写所有代码时,它工作得很好,但是当我将class(甚至一个名字space)一些对象将被破坏。

这段代码可以正常运行:

 //#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#include <v8.h>
#include <libplatform.h>


using namespace v8;

Handle<v8::Object> g_global;

// Reads a file into a v8 string. 
v8::Handle<v8::String> _ReadFile(const char* name)
{
#pragma warning(disable : 4996)
    FILE* file = fopen(name, "rb");
    if (file == NULL) return v8::Handle<v8::String>();

    fseek(file, 0, SEEK_END);
    int size = ftell(file);
    rewind(file);

    char* chars = new char[size + 1];
    chars[size] = '[=10=]';
    for (int i = 0; i < size;)
    {
        int read = fread(&chars[i], 1, size - i, file);
        i += read;
    }
    fclose(file);
    v8::Handle<v8::String> result = v8::String::NewFromUtf8(g_global->GetIsolate(), chars);
    delete[] chars;
    return result;

}




Handle<v8::Value> CallJSFunction( std::string funcName, Handle<Value> argList[], unsigned int argCount) {


Handle<v8::Object> global = g_global;
// Create value for the return of the JS function
Handle<Value> js_result;
// Grab JS function out of file
Handle<v8::Value> value = global->Get(String::NewFromUtf8(global->GetIsolate(), funcName.c_str()));
// Cast value to v8::Function
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
}

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
    virtual void *Allocate(size_t length) {
        void *data = AllocateUninitialized(length);
        return data == NULL ? data : memset(data, 0, length);
    }
    virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
    virtual void Free(void *data, size_t) { free(data); }
};


int main(int argc, char* argv[]) 
{
    // Initialize V8.
    V8::InitializeICU();
    V8::InitializeExternalStartupData(argv[0]);
    Platform* platform = platform::CreateDefaultPlatform();
    V8::InitializePlatform(platform);
    V8::Initialize();
    // Create a new Isolate and make it the current one.
    ArrayBufferAllocator allocator;
    Isolate::CreateParams create_params;
    create_params.array_buffer_allocator = &allocator;
    Isolate* isolate = Isolate::New(create_params);

        Isolate::Scope isolate_scope(isolate);
        // Create a stack-allocated handle scope.
        HandleScope handle_scope(isolate);
        // Create a new context.
        Local<Context> context = Context::New(isolate);
        // Enter the context for compiling and running the hello world script.
        Context::Scope context_scope(context);

        g_global = context->Global();

        // Try to include this js file into current context
        Local<String> source = _ReadFile(R"(somjsfile.js)");
        Local<Script> script = Script::Compile(context, source).ToLocalChecked();
        script->Run();

            //
            // functionName is a valid js code inside somjsfile.js file i test it and it's ok.
            //
            Handle<Value> js_result = CallJSFunction("functionName", nullptr, 0);
            String::Utf8Value utf8(js_result);

            printf("%s\n", *utf8);
        }

    // Dispose the isolate and tear down V8.
    isolate->Dispose();
    V8::Dispose();
    V8::ShutdownPlatform();
    delete platform;
    return 0;
}

但是如果我像这样把代码放在 class 中,我就不能调用 CallJSFunction():

因为某些对象无法访问或为空

#pragma once
#include "Common.h"

#include <v8.h>
#include <libplatform.h>

using namespace v8;

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
    virtual void *Allocate(size_t length) {
        void *data = AllocateUninitialized(length);
        return data == NULL ? data : memset(data, 0, length);
    }
    virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
    virtual void Free(void *data, size_t) { free(data); }
};

class JSUtil
{
private:
    v8::Isolate         *  m_Isolate;
    v8::Handle<v8::Object> m_global;
    v8::Local<v8::Context> m_Context;
    v8::Platform*          m_platform;
    std::string LoadFileAsString(const char* name)
    {
#pragma warning(disable : 4996)
        FILE* file = fopen(name, "rb");
        if (file == nullptr)
            return nullptr;

        fseek(file, 0, SEEK_END);
        int size = ftell(file);
        rewind(file);

        char* chars = new char[size + 1];
        chars[size] = '[=11=]';
        for (int i = 0; i < size;)
        {
            int read = fread(&chars[i], 1, size - i, file);
            i += read;
        }
        fclose(file);
        std::string result = std::string(chars);
        delete[] chars;
        return result;
    }

    bool InitV8Engine()
    {
        std::string exepath = R"(fullpath_of_exename)";
        // Initialize V8.
        v8::V8::InitializeICU();
        v8::V8::InitializeExternalStartupData(exepath.c_str());
        m_platform = v8::platform::CreateDefaultPlatform();
        v8::V8::InitializePlatform(m_platform);
        v8::V8::Initialize();


        // Create a new Isolate and make it the current one.
        ArrayBufferAllocator allocator;
        v8::Isolate::CreateParams create_params;
        create_params.array_buffer_allocator = &allocator;

        m_Isolate = v8::Isolate::New(create_params);

        v8::Isolate::Scope isolate_scope(m_Isolate);
        // Create a stack-allocated handle scope.
        v8::HandleScope handle_scope(m_Isolate);
        // Create a new context.
        m_Context = v8::Context::New(m_Isolate);
        // Enter the context for compiling and running the hello world script.
        v8::Context::Scope context_scope(m_Context);


        IncludeJSFile(m_Context->Global());
        return true;
    }

    bool Shutdown()
    {
        // Dispose the isolate and tear down V8.
        m_Isolate->Dispose();
        V8::Dispose();
        V8::ShutdownPlatform();
        delete m_platform;
    }
    bool IncludeJSFile(v8::Handle<v8::Object> global)
    {
        //
        // Try to include this js file into current context
        //
        // Create a string containing the JavaScript source code.
        std::string FileBuff = LoadFileAsString(R"(somjsfile.js)");
        v8::Local<v8::String> source = v8::String::NewFromUtf8(global->GetIsolate(), FileBuff.c_str());
        // Compile the source code.
        v8::Local<v8::Script> script = v8::Script::Compile(m_Context, source).ToLocalChecked();
        // Run the script to get the result.
        script->Run();

        return true;
    }

    v8::Handle<v8::Value> CallJSFunction(std::string funcName, v8::Handle<v8::Value> argList[], unsigned int argCount)
    {
           v8::Handle<v8::Object> global = m_global;
// Create value for the return of the JS function
v8::Handle<v8::Value> js_result;

v8::Local<v8::String> tmp = v8::String::NewFromUtf8(global->GetIsolate(), funcName.c_str());
// Grab JS function out of file
v8::Handle<v8::Value> value = global->Get(tmp);
// Cast value to v8::Function
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
    }
public:
    JSUtil()
    {
        InitV8Engine();
    }

    ~JSUtil()
    {
        Shutdown();
    }
};

您将 v8::Local<...> 个对象放入 class,但 v8::Local 对象仅在 HandleScope 中有效。 HandleScope 消失后,您的 Local 也会消失。

相反,如果您想长期保存物品,则需要将它们变成 v8::Global<...>。随着事物的移动,它们会由垃圾收集器不断更新,因此它们的成本更高,这就是为什么一切都不是全局的。

正在创建全局:

v8::Global<v8::Value> my_global(isolate, my_local);

让本地人退出:

v8::Local<v8::Value> my_local = my_global.Get(isolate);

需要注意的一点是,全局变量只能移动,因此您必须像处理 std::unique_ptr.

一样处理它们