diff --git a/src/nlv_async_worker.h b/src/nlv_async_worker.h index f6364f0..6136483 100644 --- a/src/nlv_async_worker.h +++ b/src/nlv_async_worker.h @@ -47,7 +47,6 @@ class NLVAsyncWorker : public NLVAsyncWorkerBase private: T handle_; - }; /** @@ -304,11 +303,8 @@ class NLVLookupInstanceByValueWorker : public NLVAsyncWorkerBase if (parentObject->IsObject()) { childObject->Set(Nan::New("_parent").ToLocalChecked(), parentObject); } - InstanceClass *child = Nan::ObjectWrap::Unwrap(childObject); - NLVObjectBasePtr *childPtr = new NLVObjectBasePtr(child); - child->SetParentReference(childPtr); - parent_->children_.push_back(childPtr); + child->AddToParent(parent_); v8::Local argv[] = { Nan::Null(), childObject }; callback->Call(2, argv); } diff --git a/src/nlv_object.h b/src/nlv_object.h index 9a15ada..5e951c7 100644 --- a/src/nlv_object.h +++ b/src/nlv_object.h @@ -6,37 +6,15 @@ #include #include +#include +#include +#include + using namespace node; using namespace v8; class NLVObjectBase; -// hold a reference to a "child" object in a way that can be safely invalidated -// if the child is destroyed by the GC before the parent. -class NLVObjectBasePtr -{ -public: - NLVObjectBasePtr(NLVObjectBase *ref) : ref_(ref), valid_(true) {} - bool IsValid() const { return valid_; } - NLVObjectBase* GetPointer() const { - if (!valid_) { - //Nan::ThrowReferenceError("attempt to access invalid NLVObjectBase pointer"); - return NULL; - } - - return ref_; - } - - void SetInvalid() { - ref_ = NULL; - valid_ = false; - } - -protected: - NLVObjectBase *ref_; - bool valid_; -}; - #define NLV_STRINGIFY0(v) #v #define NLV_STRINGIFY(v) NLV_STRINGIFY0(v) @@ -49,38 +27,58 @@ class NLVObjectBasePtr friend class NLVObject; -class NLVObjectBase : public Nan::ObjectWrap +class NLVObjectBase : public Nan::ObjectWrap, public std::enable_shared_from_this { public: + void AddToParent(NLVObjectBase* parent) { + parent->PushChild(shared_from_this()); + } + + void ClearChildren() { + for (auto& ptr: children_) { + if (auto object = ptr.lock()) { + object->ClearHandle(); + object->ClearChildren(); + } + } + children_.clear(); + } + virtual void ClearHandle() = 0; - virtual void ClearChildren() = 0; - virtual void SetParentReference(NLVObjectBasePtr *parentReference) = 0; - std::vector children_; + void PushChild(const std::shared_ptr& child) { + children_.emplace_front(child); + } + std::forward_list> children_; }; template class NLVObject : public NLVObjectBase { + std::shared_ptr selfPtr; public: typedef HandleType handle_type; - typedef typename std::remove_pointer::type HandleValue; - - NLVObject(HandleType handle) : handle_(handle, CleanupHandler::cleanup), parentReference_(NULL) {} + + NLVObject(HandleType handle) : handle_(handle, CleanupHandler::cleanup) { + } + ~NLVObject() { - // calling virtual ClearHandle() will break if overridden by subclasses - ClearHandle(); - if (parentReference_ != NULL) { - parentReference_->SetInvalid(); - } + } + + void RegisterSelf() { + selfPtr = shared_from_this(); } static v8::Local NewInstance(handle_type handle) { Nan::EscapableHandleScope scope; Local ctor = Nan::New(ParentClass::constructor); Local object = Nan::NewInstance(ctor).ToLocalChecked(); - ParentClass *class_instance = new ParentClass(handle); + auto shared = std::shared_ptr(new ParentClass(handle), [=](ParentClass*) { + // here we can now if GC has destroyed our object + }); + ParentClass *class_instance = shared.get(); + class_instance->RegisterSelf(); class_instance->Wrap(object); return scope.Escape(object); } @@ -92,8 +90,7 @@ class NLVObject : public NLVObjectBase const HandleType virHandle() const { return handle_.get(); - } - + } NAN_INLINE static ParentClass* Unwrap(v8::Local val) { if(!ParentClass::IsInstanceOf(val)) { @@ -126,34 +123,12 @@ class NLVObject : public NLVObjectBase return Unwrap(val)->virHandle(); } - virtual void ClearHandle() { + void ClearHandle() { handle_.reset(); } - virtual void ClearChildren() { - std::vector::const_iterator it; - for (it = children_.begin(); it != children_.end(); ++it) { - NLVObjectBasePtr *ptr = *it; - if (ptr->IsValid()) { - NLVObjectBase *obj = ptr->GetPointer(); - obj->ClearChildren(); - obj->ClearHandle(); - obj->SetParentReference(NULL); - delete ptr; - } - } - - children_.clear(); - } - - virtual void SetParentReference(NLVObjectBasePtr *parentReference) { - parentReference_ = parentReference; - } - protected: std::unique_ptr handle_; - NLVObjectBasePtr* parentReference_; - }; namespace NLV { diff --git a/src/worker.h b/src/worker.h index 78c62b7..8f8d97d 100644 --- a/src/worker.h +++ b/src/worker.h @@ -58,17 +58,13 @@ namespace NLV { Local childObject = T::NewInstance(val); Local parentObject = worker->GetFromPersistent("parent"); T* child = T::Unwrap(childObject); - NLVObjectBasePtr* childPtr = new NLVObjectBasePtr(child); if (parentObject->IsObject()) { childObject->Set(Nan::New("_parent").ToLocalChecked(), parentObject); auto parent = Nan::ObjectWrap::Unwrap(parentObject->ToObject()); - if (parent) { - parent->children_.push_back(childPtr); - } + child->AddToParent(parent); } - child->SetParentReference(childPtr); if (try_catch.HasCaught()) { v8::Local argv[] = { try_catch.Exception() };