I want to create an error object. But there is no v8::Error::New() How can I create an error object?
v8::Handle< v8::Value > result = v8::Undefined();
v8::Handle< v8::Value > error = v8::Undefined();
if(m_errorMsg.empty())
{
// Not error
}
else
{
// HERE: Instead of a string I want an error object.
error = v8::String::New( m_errorMsg.c_str() );
}
v8::Handle< v8::Value > argv[] = { error, result };
m_callback->Call(v8::Context::GetCurrent()->Global(), 2, argv);
actually the api was changed. now, you can throw an exception in this way
...
Isolate* isolate = args.GetIsolate();
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Your error message")));
...
This is not specific to Node, you can just use the ThrowException method from the V8 API. It requires one parameter of type Exception which you can create with one of the static methods on the Exception class.
There are examples on how to do it in this Node tutorial but feel free to check out my code on GitHub too.
ThrowException(Exception::TypeError(String::New("This is an error, oh yes.")));
return Undefined();
NOTE: Don't forget to return with Undefined() after calling ThrowException. (Even scope.close is unnecessary in this case.)
Further reading:
documentation of the ThrowException method:
http://bespin.cz/~ondras/html/namespacev8.html#a2469af0ac719d39f77f20cf68dd9200e
documentation of the Exception class:
http://bespin.cz/~ondras/html/classv8_1_1Exception.html
As far as i know there isn't a v8::Error class but there's the v8::Exception that provides static member functions to construct different types of errors by supplying a v8::String argument.
Take a look at the v8::Exception Class Reference, that's probably what you're looking for.
I hope this helps.
Related
I am currently getting familiar with restbed for a project but ran into a problem right at the start. I admit that this might be something very trivial but still a problem for me at the time.
Restbed service requires a const callback function
void set_method_handler( const std::string& method, const std::function< void ( const std::shared_ptr< Session > ) >& callback );
The thing is that I wand to create a REST service to GET some data from a class object.
HEADER
std::shared_ptr<restbed::Resource> REST_get_test;
static void get_test_handler(const std::shared_ptr< restbed::Session > session );
CONSTRUCTOR
REST_get_test = std::make_shared< restbed::Resource >( );
REST_get_test->set_path( "/test" );
REST_get_test->set_method_handler( "GET", get_test_handler);
The handler I call is supposed to iterate through a structure (Code is not finished, but enough to illustrate the problem)
void c_module_home::get_test_handler( const std::shared_ptr< restbed::Session > session )
{
QJsonObject status;
for (auto iter = cortexDrones.begin(); iter!= cortexDrones.end(); ++iter){
}
session->close( restbed::OK, "Hello, World!", { { "Content-Length", "13" }, { "Connection", "close" } } );
}
As expected I get a:
error: invalid use of member 'project::c_module_home::cortexDrones' in static member function
Does anyone have a suggestion how to handle that? Thanks a lot!!
Long story short... it's not a very trivial problem; at least the answer behind why it's not working as expected.
get_test_handler is a static member function in a class and it cannot access non-static properties.
If get_test_handler is a non-static member function in a class it cannot function as a callback, because a member function pointer is not the same as a "normal" function pointer.
Member functions expect the this pointer to be passed as first parameter. This is done by the compiler automatically; meaning that the function signatures do not match.
In my first attempts at mainly the same thing (using restbed), on of the first thoughts was to make the handler static, but that forces you to have anything else you might access from the handler be static as well. This is not a solution in my opinion.
The solution I found after some struggling with the same problem is to wrap the handler in a lambda function; at least if you're using C++11 or greater.
Short example based on your code:
resource->set_method_handler("GET",
[&](const std::shared_ptr<restbed::Session> session) {
get_test_handler(session);
});
Main point here is not to get the idea that a lambda is a std::function; it's an unspecified type which can be assigned to a std::function (of course the type has to match).
You can find more details in the following links:
https://en.cppreference.com/w/cpp/language/lambda
https://shaharmike.com/cpp/lambdas-and-functions/
UPDATE:
I found this link which in my opinion describes best C++ lambdas: https://www.cprogramming.com/c++11/c++11-lambda-closures.html and it's a way easier read compared to the cppreference.com one.
I know this is already answered but if you do not want to use lambdas you can use std::bind.
Short example based on your code:
resource->set_method_handler("GET",std::bind(&c_module_home::get_test_handler, this, _1));
This is my first experience with downcasting in C++ and I just can't understand the problem.
AInstruction and CInstruction inherit from AssemblerInstruction.
Parser takes the info in its ctor and creates one of those derived instruction types for its mInstruction member (accessed by getInstruction). In the program, a method of the base AssemblerInstruction class is used, for happy polymorphism.
But when I want to test that the Parser has created the correct instruction, I need to query the derived instruction members, which means I need to downcast parser.getInstruction() to an AInstruction or CInstruction.
As far as I can tell this needs to be done using a bunch of pointers and references. This is how I can get the code to compile:
TEST(ParserA, parsesBuiltInConstants)
{
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
EXPECT_EQ(inst.getInstructionType(), AssemblerInstruction::InstructionType::A);
AssemblerInstruction* i = &(inst);
AInstruction* a = dynamic_cast<AInstruction*>(i);
EXPECT_EQ(a->getLine(), "R3");
}
Running this gives this error:
unknown file: error: SEH exception with code 0xc0000005 thrown in the test body.
And stepping through the code, when the debugger is on the final line of the function, a is pointing to
0x00000000 <NULL>.
I imagine this is an instance where I don't have a full enough understanding of C++, meaning that I could be making a n00b mistake. Or maybe it's some bigger crazy problem. Help?
Update
I've been able to make this work by making mInstruction into a (dumb) pointer:
// in parser, when parsing
mInstructionPtr = new AInstruction(assemblyCode.substr(1), lineNumber);
// elsewhere in AssemblerInstruction.cpp
AssemblerInstruction* AssemblyParser::getInstructionPtr() { return mInstructionPtr; }
TEST(ParserA, parsesBuiltInConstants)
{
auto ptr = Parser("#R3", 0).getInstructionPtr();
AInstruction* a = dynamic_cast<AInstruction*>(ptr);
EXPECT_EQ(a->getLine(), "R3");
}
However I have trouble implementing it with a unique_ptr:
(I'm aware that mInstruction (non-pointer) is redundant, as are two types of pointers. I'll get rid of it later when I clean all this up)
class AssemblyParser
{
public:
AssemblyParser(std::string assemblyCode, unsigned int lineNumber);
AssemblerInstruction getInstruction();
std::unique_ptr<AssemblerInstruction> getUniqueInstructionPtr();
AssemblerInstruction* getInstructionPtr();
private:
AssemblerInstruction mInstruction;
std::unique_ptr<AssemblerInstruction> mUniqueInstructionPtr;
AssemblerInstruction* mInstructionPtr;
};
// in AssemblyParser.cpp
// in parser as in example above. this works fine.
mUniqueInstructionPtr = make_unique<AInstruction>(assemblyCode.substr(1), lineNumber);
// this doesn't compile!!!
unique_ptr<AssemblerInstruction> AssemblyParser::getUniqueInstructionPtr()
{
return mUniqueInstructionPtr;
}
In getUniqueInstructionPtr, there is a squiggle under mUniqueInstructionPtr with this error:
'std::unique_ptr<AssemblerInstruction,std::default_delete>::unique_ptr(const std::unique_ptr<AssemblerInstruction,std::default_delete> &)': attempting to reference a deleted function
What!? I haven't declared any functions as deleted or defaulted!
You can not downcast an object to something which doesn't match it's dynamic type. In your code,
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
inst has a fixed type, which is AssemblerInstruction. Downcasting it to AInstruction leads to undefined behavior - manifested as crash - because that is not what it is.
If you want your getInstruction to return a dynamically-typed object, it has to return a [smart] pointer to base class, while constructing an object of derived class. Something like that (pseudo code):
std::unique_ptr<AssemblerInstruction> getInstruction(...) {
return std::make_unique<AInstruction>(...);
}
Also, if you see yourself in need of downcasting object based on a value of a class, you are doing something wrong, as you are trying to home-brew polymorphism. Most of the times it does indicate a design flaw, and should instead be done using built-in C++ polymorphic support - namely, virtual functions.
I'm trying to work with a C interface generated using camlidl. The library I'm working with returns an error code by allocating and filling an in/out argument char* error_message and returning it. After the function call, I check the error code for non-zero... if true, I call caml_failwith(error_message) to throw an OCaml exception using the library error message.
However, I started digging a bit, because throwing the exception looks as though it will terminate the function and never free the error message. Consider this mock code:
/* in the C stub function call... */
double _res;
int error = 0;
char* error_message = NULL;
// if this function errors, it will set error to non-zero
// and strdup something into error_message
_res = call_library_function(&error, error_message);
if (error) {
caml_failwith(error_message);
free(error_message); // NEVER CALLED?
}
/* code to copy result to an OCaml value and return */
The exception func caml_failwith(s) implementation is in runtime/fail_*.c, but it basically just calls caml_raise_with_string, which is:
CAMLparam1(tag);
value v_msg = caml_copy_string(msg);
caml_raise_with_arg(tag, v_msg);
CAMLnoreturn;
So, it copies the string to the OCaml value with caml_copy_string, and then raises the arg and no-returns. In short, error_message is lost.
...Right? What am I missing here... I could use canned strings but that makes dynamic error messages impossible. I could maybe use static char*, though it's not thread safe any more without a bunch of work. Is there any way to call caml_failwith, using a plain old dynamic char*, and not have it cause a leak?
EDIT: I thought of one solution...
char error_message_buf[100] = {'\0'};
double _res;
// ... rest of local vars and service call ...
if (error) {
strncpy(error_message_buf, error_message, 99)
free(error_message);
caml_failwith(error_message_buf);
}
... but man that's ugly. strncpy to the stack just to turn around and caml_copy_string again? Plus, it sets a hardcoded cap on error message length. Still, if it's the only way not to leak...
caml_failwith() is designed so you can call it with a constant string, which is a very common case:
caml_failwith("float_of_string");
So, you can't expect it to free its argument.
I don't personally consider this a space leak, it's just how the function is designed.
Your solution of copying the message first seems reasonable (and not particularly ugly) to me.
(This, in essence, is why I switched from C to OCaml many years ago.)
I'm trying to expose my std::map<std::string, std::string> as a class property to Lua. I've set this method for my getter and setter:
luabind::object FakeScript::GetSetProperties()
{
luabind::object table = luabind::newtable(L);
luabind::object metatable = luabind::newtable(L);
metatable["__index"] = &this->GetMeta;
metatable["__newindex"] = &this->SetMeta;
luabind::setmetatable<luabind::object, luabind::object>(table, metatable);
return table;
}
This way it makes me able to do something like this in Lua:
player.scripts["movement"].properties["stat"] = "idle"
print(player.scripts["movement"].properties["stat"])
However, the code I've provided in C++ doesn't getting compiled. It tells me there is an ambiguous call to overloaded function at this line metatable["__index"] = &this->GetMeta; and the line after it. I'm not sure that I'm doing this correctly.
Error message:
error C2668: 'luabind::detail::check_const_pointer' :
ambiguous call to overloaded function
c:\libraries\luabind-0.9.1\references\luabind\include\luabind\detail\instance_holder.hpp 75
These are SetMeta and GetMeta in FakeScript:
static void GetMeta();
static void SetMeta();
Previously I was doing this for getter method:
luabind::object FakeScript::getProp()
{
luabind::object obj = luabind::newtable(L);
for(auto i = this->properties.begin(); i != this->properties.end(); i++)
{
obj[i->first] = i->second;
}
return obj;
}
This works fine, but it's not letting me to use setter method. For example:
player.scripts["movement"].properties["stat"] = "idle"
print(player.scripts["movement"].properties["stat"])
In this code it just going to trigger getter method in both lines. Although if it was letting me to use setter, I wouldn't be able to get key from properties which it is ["stat"] right here.
Is there any expert on LuaBind here? I've seen most of people say they've never worked with it before.
You need to use the (undocumented) make_function() to make objects from functions.
metatable["__index"] = luabind::make_function(L, &this->GetMeta);
metatable["__newindex"] = luabind::make_function(L, &this->GetMeta);
Unfortunately, this (the simplest) overload of make_function is broken, but you just need to insert f as the second parameter in make_function.hpp.
I am writing some basic code to experiment with Angelscript, however I cannot get even the simplest functions to work correctly. Here is the basic code block:
class Engine {
public:
void print(std::string&);
};
Engine::print(std::string &msg)
{
cout<<msg.c_str()<<endl;
}
Here is the actual code that initializes and registers C functions for Angelscript:
int r;
asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
r = engine->SetMessageCallback(asMETHOD(Engine,MessageCallback), this,asCALL_THISCALL);
assert( r >= 0 );
RegisterStdString(engine);
r = engine->RegisterObjectType("Engine", 0, asOBJ_APP_CLASS_CONSTRUCTOR);
cout<<"r was: "<<r<<endl;
assert( r >= 0 );
r = engine->RegisterObjectMethod("Engine","void print(const string &in)", asMETHOD(Engine,print), asCALL_THISCALL);
assert( r >= 0 );
At first I did not have the function "RegisterObjectType()" present, so running the program would throw a "'Engine' is not a valid type" error even though it was a valid class. So I found a function called "RegisterObjectType()" and implemented it as above and now it's throwing a "Invalid Flag" error on the 'RegisterObjectType()' function in the last field. I've tried all the class flags and it still throws this error.
What is the proper method for registering a class method into Angelscript? The documentation example didn't seem to work. It seems to snip out everything except the actual function it is explaining, for example, it did not hint about registering object types with the class method registration code. Or it was not very clear about it.
I should mention that all the errors encountered are runtime errors thrown by the angelscript libraries and not compiler errors.
Thanks!
The as_OBJ_APP_CLASS_CONSTRUCTOR is not proper flag, it should be used combined with other as_OBJ_APP... flags. Check this for example (bit outdated), and clarifications of ways to register object type: http://www.darawk.com/code/CoHClient/Angelscript/sdk/docs/articles/register_object.html.
Of course manual is your best friend:
http://www.angelcode.com/angelscript/sdk/docs/manual/index.html
(Using Angelscript->Registering the application interface->Registering an object type)