Open jcmonnin opened 6 years ago
Hi Jean-Claude,
Thank you for the detailed issue description.
References to wrapped class as function arguments should be converted with convert_ref in ptrtraits. There is a case in the [`v8pp::class` test](https://github.com/pmed/v8pp/blob/master/test/test_class.cpp#L49).
The cause of issue could be due to const
qualifiers for the argument references. I will add your code into the test case in order to check it.
This checking of traits types in find()
function was added to prevent implicit conversions between different pointer types. But if such conversions seems to be handy, we could try to enable them. Maybe by adding helper functions into the traits classes for raw_ptr_traits
to shared_ptr_traits
and vice versa, similar to convert_ref
templates.
Best regards, Pavel
Hi Pavel,
Thanks for the reply. You are right, calling a function taking a reference actually does work. I was taking wrong conclusions for some reason. I clearly tried to add two many things in my test case.
The problem with the call to a function/method taking a raw pointer remains.
Given my initial post is too big and contains wrong things, I propose to close it and I will reopen another one with a more concise example about it. Is that ok or do you want to continue on this issue number?
Thanks, Jean-Claude
Hi Jean-Claude,
I think it’s ok to continue in this issue, thank you.
чт, 19 июля 2018 г. в 12:04, Jean-Claude Monnin notifications@github.com:
Hi Pavel,
Thanks for the reply. You are right, calling a function taking a reference actually does work. I was taking wrong conclusions for some reason. I clearly tried to add two many things in my test case.
The problem with the call to a function/method taking a raw pointer remains.
Given my initial post is too big and contains wrong things, I propose to close it and I will reopen another one with a more concise example about it. Is that ok or do you want to continue on this issue number?
Thanks, Jean-Claude
— You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/pmed/v8pp/issues/79#issuecomment-406224748, or mute the thread https://github.com/notifications/unsubscribe-auth/ABEgUrvI45-9cMaEFbiP5ZDCQGDTOWtCks5uIFmwgaJpZM4VO1PH .
-- Sincerely, Pavel
Hi Pavel,
I'd like to come back to calling a function taking a raw pointer (when the class has been declared with v8pp::shared_ptr_traits
). For the example above this would be a function like:
void printTestRawPtr(const Test* test)
This fails because unwrap_object
calls classes::find
which throws exception because of mismatching traits.
In the API I need to bind these type of functions are pretty common and I need to bind my classes to JavaScript with v8pp::shared_ptr_traits
because there is no other clean way to express the ownership if the instances.
As said in the initial comment, commenting out some lines in classes::find
make the test case go through, but the implementation is not clean (I think it would be undefined behaviour to cast the instance to a different type than what it has been instantiated):
template<typename Traits>
static object_registry<Traits>& find(v8::Isolate* isolate, type_info const& type)
{
classes* info = instance(operation::get, isolate);
type_info const& traits = type_id<Traits>();
if (info)
{
auto it = info->find(type);
if (it != info->classes_.end())
{
// if ((*it)->traits != traits)
// {
// throw std::runtime_error((*it)->class_name()
// + " is already registered in isolate "
// + pointer_str(isolate) + " before of "
// + class_info(type, traits).class_name());
// }
return *static_cast<object_registry<Traits>*>(it->get());
}
}
//assert(false && "class not registered");
throw std::runtime_error(class_info(type, traits).class_name()
+ " is not registered in isolate " + pointer_str(isolate));
}
If you see a strait-forward way to fix it, please let me know.
Otherwise maybe the suggestions below are helpful (hopefully it's not too much off topic);
In the old days, I was using luabind to bind C++ classes lua code (it was pre C+11, so this was with boost::shared_ptr). It was handling the case above. Nowadays sol2 is the reference for binding lua code and it has very flexible support for smart pointers. It might be worthwhile to have a look there:
http://luabind.sourceforge.net/docs.html#class_smart_pointers http://sol2.readthedocs.io/en/latest/api/unique_usertype_traits.html
When a smart pointer is used, the smart pointer is not replacement of the raw pointer as in v8pp, but an additional concept (holder_type/actual_type). The traits are defined independently of the wrapper class. This allows more flexibility. It's not necessary to make the choice to either use shared_ptr or raw pointers everywhere. It's possible to mix things more freely (and also supports other smart pointer types than std::shared_ptr):
http://sol2.readthedocs.io/en/latest/tutorial/all-the-things.html#c-classes-from-c
Possibly this doesn't really translate to v8pp/JavaScript, but maybe you find some of the ideas useful.
I bind my C++ types with
shared_ptr_traits
when there is shared ownership in between C++ and JavaScript or if I need to pass ownership from JavaScript to C++. This works well, but I have to apply some workarounds. When having such a type bound withshared_ptr
, it's quite common to have to call API's that expect an object reference or a raw pointer. This currently doesn't work with v8pp.Here is a short summary of the main issue: When a class is bound to JavaScript with
shared_ptr
we cannot call a function taking a reference:
More complete example:
Using
v8pp::shared_ptr_traits
When initialising the context with
bindTest<v8pp::shared_ptr_traits>(isolate);
, I get following results (note: the situation with the return values is there for completeness, but not the main issue):Calling function taking
shared_ptr
gives the expected result (first line is
std::cout
, 2nd line is what the script expression returns)Calling function taking raw pointer
When calling function taking raw pointer, I get a C++ exception. Ideally, this would work. Admittedly, the return value is a bit more complicated. I guess it would be ok if it throws a C++ exception when doing the return value (although theoretically it could get a shared_prt instance if the class derives from
std::enable_shared_from_this
).Calling function taking reference
When calling function taking a reference, I get a C++ exception. This is a quite common case which should work. The return value situation is #39.
Using
v8pp::raw_ptr_traits
As a comparison, here is what I get when initialising the context with
bindTest<v8pp::raw_ptr_traits>(isolate);
:Calling function taking
shared_ptr
This gives a C++ exception. Generally, this call makes no sense. Strictly speaking this would be possible if the class derives from
std::enable_shared_from_this
, however this use case is probably not relevant in practice.Calling function taking raw pointer
gives the expected result
Calling function taking reference
Calling a reference is possible. Return value issue is #39. It looks like earlier versions of v8pp were returning
undefined
whereas now it throws a C++ exception.Current workaround
To solve the main issue of calling a function taking a reference or pointer as argument, I have a very ugly workaround. When I comment out the traits check in
classes::find
, then it seems to do what I want. The problem is that this relies on undefined behaviour (I don't think that it's safe to convert an instance to a different type withstatic_cast
). So I would be keen to have a more permanent solution that this: