Prevent v8::Local value from being garbage collected - c++

I have a function that stores the value of an argument to an std::vector<v8::Local<v8::Value>> property of a C++ class exposes as an ObjectWrap like this:
NAN_METHOD(MyObject::Write) {
MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.This());
obj->data.push_back(info[0]);
}
However, when I try to read back the value from another C++ function, the value is lost, and becomes undefined.
I'm passing a number to MyObject::Write, and I can confirm info[0]->IsNumber() returns true before pushing it to the vector, however when reading it back, the value it not a number, and in fact returns false for all the types I tested using Is<Type> methods from v8::Value, but still returns true for BooleanValue().
My guess is that the variable is being garbage collected after MyObject::Write returns, however I have no idea how to prevent this from happening.
I'm currently trying to initialise the value as a Persistent value. I tried the following attempts without success:
Nan::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
Nan::Persistent<v8::Value> persistent(info[0]);
Nan::CopyablePersistentTraits::Copy(persistent, p);
And:
v8::Isolate *isolate = info.GetIsolate();
v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> persistent(isolate, info[0]);
But getting tons of C++ errors.

I was running into problems untangling this mess myself. There's a lot of template stuff going on here that we both missed. Here was the solution I found most readable:
// Define the copyable persistent
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
// Create the local value
auto val = v8::Local<v8::Value>::New(
v8::Isolate::GetCurrent(), //< Isolate required
v8::Integer::New(v8::Isolate::GetCurrent(), v) //< Isolate required
);
// Reset() is a TEMPLATE FUNCTION, you have to template it with the same
// template type parameter as the v8::Local you are passing
p.Reset<v8::Value>(v8::Isolate::GetCurrent(), val); //< Isolate required
By "info" I assume you are referring to a v8::FunctionCallbackInfo reference. If so the above code would collapse to the following:
void SomeFunc(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
}
Because the persistent is now copyable you can do things like store it inside a standard library container. This was my use case. This is an example of storing a value in a vector:
std::vector<v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent> vect;
void AccumulateData(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
vect.push_back(p);
}
I hope this helps someone out there.

If you plan on storing v8 values in C++, you need to make them persistent instead of local so they're independent of handle scope and not garbage-collected when the handle scope is released.
Nan has version-independant wrappers for v8::Persistent and Co. Because of using inside std::vector<>, you'll also need to initialize Nan::Persistent with Nan::CopyablePersistentTraits so it becomes copyable (or make an own reference-counted container for it).

Related

free data asynchronously in c++

I get a data structure like this:
struct My_data
{
MyArray<float> points;
MyArray<float> normals;
MyArray<float> uvCoords;
};
This function can be used to free them:
void ClearAlembicData(My_data* myData)
{
myData->points.clear();
myData->normals.clear();
myData->uvCoords.clear();
}
I want to asynchronously clean the myData so that the program will not wait util all the xxx.clear() are done. Here is my actual code:
My_data myData;
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
ClearAlembicData(&myData);
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
Could you show me how to do it in C++? thanks
Depending on the definition of MyArray, this will either cause undefined behavior or be completely pointless.
If the container is thread-safe, it will block your push_back while the clear is being executed in the other thread (making the 'clearing it asynchronously' completely pointless), if it is not, you are introducing a race condition, which might even end up crashing your program, because you would be concurrently manipulating a shared resource. (Not a good idea).
If you still want to do it, here is a way that might work:
Make 'myData' into a pointer and operate on that.
Upon wanting to clear, store that pointer in another pointer variable and replace the pointer with new My_Data.
Pass the stored pointer to your asynchronous 'free' function.
Continue to work with your new data structure in the original thread.
This way, you are not working on a shared resource and asynchronous freeing becomes feasible.
As for 'how to', if you've got C++11, something like this would work (Pseudo-Code).
My_data *myData = new My_data();
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
std::thread([=](){ ClearAlembicData(myData); delete myData; }).detach();
myData = new My_data()
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
delete myData;
One of the solutions, implement MyArray::swap(MyArray&). Then
void ClearAlembicData(My_data* myData)
{
MyArray<float> old_points;
MyArray<float> old_normal;
MyArray<float> old_coords;
// Fast swap, myData arrays become empty
myData->points.swap(old_points);
myData->normals.clear(old_normals);
myData->uvCoords.clear(old_coords);
// Assumed to be passed to async function
old_points.clear();
old_normals.clear();
old_coords.clear();
}
There is no enough information about MyArray abilities, such as support of move semantics, a real function clear, thus this is just an idea.
If MyArray is a wrapper around std::vector, know that the clear() operation is O(1) as float is trivially destructible and the compiler can eliminate the loop that destroys elements individually.
If it is not, consider implementing MyArray.clear() such that it marks the container as having a non-zero capacity yet zero contents. As stated above, std::vector accomplishes this by simply setting slots_available = capacity.

c++ passing json object by reference

In the below code, I am taking requests from a client, put them together on a json object on my server class and sending it to a pusher(directly connected to a website, putting my data in there so I can search data easily)
The code is working perfectly fine, but my manager said that I need to pass json by reference in this code, and I have no idea what to do.
On Server Class:
grpc::Status RouteGuideImpl::PubEvent(grpc::ServerContext *context,
const events::PubEventRequest *request,
events::PubEventResponse *response){
for(int i=0; i<request->event_size();i++){
nhollman::json object;
auto message = request->events(i);
object["uuid"]=message.uuid();
object["topic"]=message.type();
pusher.jsonCollector(obj);
}
...
}
On Pusher Class:
private:
nholmann::json queue = nlohmann::json::array();
public:
void Pusher::jsonCollector(nlohmann::json dump){
queue.push_back(dump);
}
void Pusher::curlPusher(){
std::string str = queue.dump();
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, str.data());
...
}
As much as I understand, I need to send the json object by reference. How can I do that?
The simple answer is to change
void Pusher::jsonCollector(nlohmann::json dump)
to
void Pusher::jsonCollector(const nlohmann::json& dump)
(note that if this is inside the class then Pusher:: is a non-standard visual studio extension).
This will reduce the number of times the object is copied from 2 to 1 however you can avoid the copy completely by using std::move:
void Pusher::jsonCollector(nlohmann::json dump){
queue.push_back(std::move(dump));
}
And call it with:
pusher.jsonCollector(std::move(obj));
If you want to enforce this behaviour to ensure that callers of jsonCollector always use std::move you can change jsonCollector to:
void Pusher::jsonCollector(nlohmann::json&& dump){
queue.push_back(std::move(dump));
}
Well, references are one of the many, many features, that distinguishes C from C++.
In other languages, like python or java, when you pass an object (not basic types) to a function and change it there, it is changed in the caller entity as well. In these languages, you don't have pointers, but you need to pass the object, not a copy.
That's what you have with references in C++. They are used like value types, but they are no copy.
Pointers can be nullptr (or NULL in C), references cannot. The address a pointer points to can be changed (assigned), you cannot change what object a reference refers to.
Have a look at this https://en.cppreference.com/w/cpp/language/reference for more information.

what /can/ you return from a function .. and expect it to be alive at arrival?

Once again I got cought on expecting a function to return a proper value and then be disapointed .. getting odd behavior and misleading debug-information instead.
It's fairly well known, that you cannot return a local variable from a function and expect it to arrive as you would expect. Testing
int i=2;
int k=4;
return make_pair<int,int>(i*i,k*k);
Does indeed return something respectable. But using more elaborate objects than simple types seems to catch me every time.
So, is there any formality that I can use for discriminating on what can and what cannot be returned safely from a function?
----------- added on edit: ------------
Here is the example that does not work, taken brutally out of context.
Problem-context is a (to be GUI) tree of rectangles for the screen.
Class node inherits from a base (rectangle) containing 3 pointers to plain types (again, used to make values stick) .. the base uses new in constructor
pair<node,node> node_handler::split( vector<node>::iterator& this_node, double ratio, bool as_horizontal ){
//this_node becomes parents to the split-twins
this_node->my_ratio=ratio;
double firstW, firstH;
double secW, secH;
glm::dvec2 afirst, asecond;
if(as_horizontal ){
firstW = *this_node->plWidth*LETTER_PIXEL_WIDTH;
firstH = *this_node->plHeight*LINE_PIXEL_HEIGHT*ratio;
afirst = *this_node->pPoint;
secW = firstW;
secH = LINE_PIXEL_HEIGHT*(*this_node->plHeight)*(1.0d-ratio);
asecond= afirst+glm::dvec2(0.0d, firstH);
}
else{
firstW = ratio*(*this_node->plWidth)*LETTER_PIXEL_WIDTH;
firstH = *this_node->plHeight*LINE_PIXEL_HEIGHT;
afirst = *this_node->pPoint;
secW = (1.0d*ratio)*(*this_node->plWidth)*LETTER_PIXEL_WIDTH;
secH = firstH;
asecond= afirst+glm::dvec2(firstW,0.0d);
}
return make_pair<node,node>( node(afirst ,firstW, firstH) , node(asecond ,secW, secH) ) ;
}
Technically, you can return anything from a function.
Now when you return a pointer or a reference to something that is only local, then you have a problem.
Solutions:
Return copies (OK with copy elision anyway)
Return shared_ptr<>/unique-ptr<> for something that must not be copied.
Return only basic types and pass to the function a reference to an object that might be modified.
Do not create something in the function that needs to be manually destroyed layer (say, a pointer created with new).
It's dawning on me, that classes containing pointer-members reasonably has to have custom copy/assignment operators. I never got to grips with the "rho" variable referred to in the books I read at the time ... "right_hand_object" it must be! That's my epiphany. It was following the business of the constructors and your talk of copyable objects that squeezed this old rho-problem of mine.
I'm sorry for having spread my frustration on you.

How can I calculate a hash/checksum/fingerprint of an object in c++?

How can I calculate a hash/checksum/fingerprint of an object in c++?
Requirements:
The function must be 'injective'(*). In other words, there should be no two different input objects, that return the same hash/checksum/fingerprint.
Background:
I am trying to come up with a simple pattern for checking whether or not an entity object has been changed since it was constructed. (In order to know which objects need to be updated in the database).
Note that I specifically do not want to mark the object as changed in my setters or anywhere else.
I am considering the following pattern: In short, every entity object that should be persisted, has a member function "bool is_changed()". Changed, in this context, means changed since the objects' constructor was called.
Note: My motivation for all this is to avoid the boilerplate code that comes with marking objects as clean/dirty or doing a member by member comparison. In other words, reduce risk of human error.
(Warning: psudo c++ code ahead. I have not tried compiling it).
class Foo {
private:
std::string my_string;
// Assume the "fingerprint" is of type long.
long original_fingerprint;
long current_fingerprint()
{
// *** Suggestions on which algorithm to use here? ***
}
public:
Foo(const std::string& my_string) :
my_string(my_string)
{
original_fingerprint = current_fingerprint();
}
bool is_changed() const
{
// If new calculation of fingerprint is different from the one
// calculated in the constructor, then the object has
// been changed in some way.
return current_fingerprint() != original_fingerprint;
}
void set_my_string(const std::string& new_string)
{
my_string = new_string;
}
}
void client_code()
{
auto foo = Foo("Initial string");
// should now return **false** because
// the object has not yet been changed:
foo.is_changed();
foo.set_my_string("Changed string");
// should now return **true** because
// the object has been changed:
foo.is_changed();
}
(*) In practice, not necessarily in theory (like uuids are not unique in theory).
You can use the CRC32 algorithm from Boost. Feed it with the memory locations of the data you want to checksum. You could use a hash for this, but hashes are cryptographic functions intended to guard against intentional data corruption and are slower. A CRC performs better.
For this example, I've added another data member to Foo:
int my_integer;
And this is how you would checksum both my_string and my_integer:
#include <boost/crc.hpp>
// ...
long current_fingerprint()
{
boost::crc_32_type crc32;
crc32.process_bytes(my_string.data(), my_string.length());
crc32.process_bytes(&my_integer, sizeof(my_integer));
return crc32.checksum();
}
However, now we're left with the issue of two objects having the same fingerprint if my_string and my_integer are equal. To fix this, we should include the address of the object in the CRC, since C++ guarantees that different objects will have different addresses.
One would think we can use:
process_bytes(&this, sizeof(this));
to do it, but we can't since this is an rvalue and thus we can't take its address. So we need to store the address in a variable instead:
long current_fingerprint()
{
boost::crc_32_type crc32;
void* this_ptr = this;
crc32.process_bytes(&this_ptr, sizeof(this_ptr));
crc32.process_bytes(my_string.data(), my_string.length());
crc32.process_bytes(&my_integer, sizeof(my_integer));
return crc32.checksum();
}
Such a function does not exist, at least not in the context that you are requesting.
The STL provides hash functions for basic types (std::hash), and you could use these to implement a hash function for your objects using any reasonable hashing algorithm.
However, you seem to be looking for an injective function, which causes a problem. Essentially, to have an injective function, it would be necessary to have an output of size greater or equal to that of the object you are considering, since otherwise (from the pigeon hole principle) there would be two inputs that give the same output. Given that, the most sensible option would be to just do a straight-up comparison of the object to some sort of reference object.

How to store inside a queue a unique_ptr of object which is located inside a vector

So I am building a simulator in order to simulate some load balancing algorithms. I have created 2 vectors of Cores and Dispatchers as shown below:
std::vector<std::unique_ptr<Dispatcher> > vDisp;
std::vector<std::unique_ptr<Core> > vCore;
The class dispatcher has a queue for the cores in order to assign to them the jobs.
std::queue<Core> disp_core_queue;
Plus I have some functions in order to handle this queue:
void add_core_q(Core& p){ disp_core_queue.push(p); }
Core get_core_q(){ return disp_core_queue.front(); }
When the program initializes I populate the cores and disps like this:
for (auto i=0; i<dispNumb; ++i)
{
vDisp.push_back(std::unique_ptr<Dispatcher> (new Dispatcher));
std::cout<<"Disp n."<<i<<" Created"<<std::endl;
}
My problem is that I cannot get a Core from the vector and store it inside a Dispatcher's queue. I have tried many ways but it seems C++ punishes me for various reasons. My last try was this one from inside the Dispatcher:
int kore = random_core();
this->add_core_q(vCore.at(kore));
Which gave this error in compile time:
error: no matching function for call to 'Dispatcher::add_core_q(_gnu_cxx::__alloc_traits > >::value_type&) '
candidate is:
void Dispatcher::add_core_q(Core&)
no known conversion for argument 1 from '__gnu_cxx::__alloc_traits > >::value_type {aka std::unique_ptr}' to 'Core&'
If anyone could give me a hint I would greatly appreciate it. Thanks in advance.
The function signature for add_core_q is taking Core&.
You are passing in a std::unique_ptr.
Your Core objects are stored inside unique_ptr's yet your add_core_q method requires a Core reference.
You could get the raw pointer from the unique_ptr and dereference it which would allow you to do this:
add_core_q(*(vCore[0]));
However you're also going to have a problem with your get_core_q method since it returns a copy of the Core object rather than a reference to the Core stored in the unique_ptr.
Personally I'd just pass around pointers rather than dereferencing things. So you'd change your add_core_q method to accept a raw pointer:
void add_core_q(Core* p){ disp_core_queue.push(p); }
Which you would use like this:
add_core_q(vCore[0].get());
You'd also have to change your queue to store pointers rather than the objects themselves:
std::queue<Core*> disp_core_queue;
And you'll need to change the return type of your get method to a pointer.
Core* get_core_q(){ return disp_core_queue.front(); }
Though if you're more comfortable with references you could return a reference instead:
Core& get_core_q(){ return *(disp_core_queue.front()); }