我想在本机NodeJS(0.11.5)扩展中创建自定义异常。我正在尝试在V8(3.20.11)中创建内置Error
类的子类。
基本上我正在寻找以下Javascript代码的C ++等价物:
function MyError(message) {
Error.apply(this, arguments);
this.message = message;
}
MyError.prototype = new Error;
MyError.prototype.name = MyError.name;
new MyError("message")
我尝试挖掘V8源代码,发现以下帮助方法似乎可以实现我想要的一部分:
Handle<Object> Factory::NewError(const char* constructor,
Handle<String> message)
不幸的是,它看起来像是一个私有API,我不明白V8能够弄清楚如何构建类似的东西。能够以与创建内置Error
实例类似的方式编写可以使用的方法会很棒,例如:
ThrowException(v8::Exception::Error(v8::String::New(msg)))
// becomes...
ThrowException(MyError(v8::String::New(msg)))
我正在寻找一个尽可能接近内置Error
类的子类的解决方案。它应该满足以下条件:
var e = new MyError("message");
assert(e instanceof MyError);
assert(e instanceof Error);
assert(e.name === "MyError");
assert(e.message === "message");
有什么建议从哪里开始?
答案 0 :(得分:1)
可能是这样的:
class Error
{
// Construction
// ============
public:
virtual ~Error() throw() {};
protected:
Error(std::exception& exception)
: m_exception(&exception)
{}
// Element Access
// ==============
public:
const char* msg() const { return m_exception->what(); }
// Message
// =======
protected:
static std::string message(const std::string& msg, const std::string& context);
static std::string message(const std::string& msg) {
return message(msg, "");
}
// Cast
// ====
protected:
template <typename Derived>
static std::exception& cast(Derived& derived) {
return static_cast<std::exception&>(derived);
}
private:
std::exception* m_exception;
};
class ErrorLogic : public std::logic_error, public Error
{
public:
static std::string info();
ErrorLogic()
: std::logic_error(message(info())), Error(cast(*this))
{}
explicit ErrorLogic(const std::string& msg)
: std::logic_error(message(msg)), Error(cast(*this))
{}
template <typename T>
ErrorLogic(const std::string& msg, const T& context)
: std::logic_error(message(msg, context)), Error(cast(*this))
{}
};
答案 1 :(得分:1)
我对NodeJS了解不多,但有一种可能性是抛出任何有意义的C ++异常,在扩展边界捕获它,使用标准的V8调用来构造适当的JavaScript异常,并调用v8::ThrowException()
。如果NodeJS不允许您的分机直接访问V8,则此方法可能不是一种选择。
这是一个示例程序,演示如何设置自定义错误类并从C ++实例化它。希望NodeJS为您提供足够的V8访问权限以执行类似操作:
#include "v8.h"
#include <iostream>
static void Print(v8::Handle<v8::Value> value)
{
std::cout << *v8::String::Utf8Value(value) << std::endl;
}
static v8::Local<v8::Value> RunScript(const char* code)
{
return v8::Script::Compile(v8::String::New(code))->Run();
}
static void RunTest(v8::Isolate* isolate)
{
// setup
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
auto context = v8::Context::New(isolate);
v8::Context::Scope contextScope(context);
// create custom error class/function
auto code =
"function MyError(message) {"
"Error.apply(this, arguments);"
"this.message = message;"
"}"
"MyError.prototype = new Error;"
"MyError.prototype.name = MyError.name;"
"MyError";
auto errorFunc = RunScript(code)->ToObject();
// create custom error instance
auto message = v8::String::New("message");
v8::Handle<v8::Value> args[] = { message };
auto error = errorFunc->CallAsConstructor(1, args);
// validate custom error instance
context->Global()->Set(v8::String::New("e"), error);
Print(RunScript("e instanceof MyError"));
Print(RunScript("e instanceof Error"));
Print(RunScript("e.name === 'MyError'"));
Print(RunScript("e.message === 'message'"));
}
void main(void)
{
auto isolate = v8::Isolate::New();
RunTest(isolate);
isolate->Dispose();
}