CXSafePointer
From cxwiki
CXSafePointer is a templated class which acts equivalently to a C pointer but which automatically becomes nullptr if the referenced object is deleted. The referenced object must derived from CXSafePointerTarget.
CXSafePointer<T> is designed to act in a manner syntactically equivalent to T* where possible.
Restrictions
CXSafePointer objects have limited internal type safety. This amounts to them being roughly equivalent to a C pointer:
- They may be assigned safely from multiple threads if no specific ordering guarantees are required.
- They can be queried safely from any thread.
- However the referenced object could be destroyed on another thread after you query it, but before you try to use it.
- It is considered an error to create a CXSafePointer reference to an object which is already undergoing destruction.
- Taking a CXSafePointer reference to an object, on any thread, is fine as long as you have ownership of the object at the time.
- Detaching CXSafePointer references from a CXSafePointerTarget is fine, even if those references are held by another thread, as long as the other thread is not making blind assumptions about their contents.
- For example, this is bad:if (myPtr) myPtr->CallSomething();
- This is fine as long as the object isnt actually being destroyed: if (MyObj* obj = myPtr) obj->CallSomething();
- If you actually destroy the underlying object, then there are no thread-safety guarantes. The CXSafePointer will become null, but the other threads may be in the process of executing methods on the object (etc.)
In practice, the limited thread-safety guarantees mean that it is hard to use CXSafePointer across threads. Where they come in useful is the following scenario:
- Thread A creates an object, retains a reference.
- Thread A creates a CXSafePointer and passes it to thread B.
- Note that it is safe for thread B to hold the smart pointer, but not safe for thread B to access through the smart pointer.
- Thread A optionally destroys the object.
- Thread B passes the CXSafePointer back to thread A.
- Thread A can safely test whether the object still exists and can safely access it if does.
This scenario is fairly common for certain types of lambda:
// We are on the main thread.
CXSafePointer<MyObj> obj = ...;
CXWorkerHost::EnqueueTask(nullptr, [obj] {
auto data = DoSomething(); // note that we can't use 'obj' safely here.
CXWorkerHost::EnqueueTaskOnMainThread(nullptr, [obj, data] {
if (obj)
obj->NotifyCompletion(data);
});
});