Files
bitsery/doc/design/pointers.md
2019-06-27 11:30:34 +03:00

3.6 KiB

document in progress

Extensions

Raw pointers are managed by three extensions:

  • PointerOwner - manages a lifetime of the pointer, creates or destroys if required.
  • PointerObserver - doesn't own pointer so it doesn't create or destroy anything.
  • ReferencedByPointer - when a non-owning pointer (PointerObserver) points to reference type, this extension marks this object as a valid target for PointerObserver.

"Smart" pointers, from c++ standard lib (std), are managed by:

  • StdSmartPtr - can accept unique_ptr, shared_ptr and weak_ptr

Implementation details

All aforementioned extensions derive from single base class PointerObjectExtensionBase. This base class accepts three template parameters that customise its behaviour.

  • TPtrManager\<T\> - describes how particular pointer type should be handled: pointer creation/destruction describes a type of pointer (e.g. owning, shared, observer), and how to actually get value for pointer object. This is the place to start if you want to implement pointer support for your custom type. <T> is type of pointer object, e.g. std::unique_ptr<MyType>, MyType*
  • TPolymorphicContext\<RTTI\> - provides the functionality to register class hierarchies for your types with serializer, and deserializer, in order to polymorphically serialize/deserialize objects. <RTTI> template parameter provides runtime information about a type that is used to construct class hierarchies and save them to read/write them to buffer.
  • RTTI - this template parameter provides information if a type is polymorphic, and if it is, then it is used in TPolymorphicContext\<RTTI\>. Some pointer managers, like PointerObserver and ReferencedByPointer never requires polymorphic context. In these cases, you need to provide RTTI that will return isPolymorphic=false for all types. By default all pointers extensions use StandardRTTI from "/ext/utils/rtti_utils.h" that internally uses typeid and dynamic_cast. If your environment doesn't allow RTTI, you can provide your own RTTI for your types.

Allocators

Allocation is implemented using dynamic type for allocator (similar to std::pmr::memory_resource from c++17), and it is called MemResourceBase from "ext/utils/memory_allocator.h". The core difference between standard one and this allocator is that it has additional size_t typeId field for allocate and deallocate methods, this value is returned from RTTI. There are few options to customise pointer allocation for your pointers:

  • provide default allocator in PointerLinkingContext by calling setMemResource.
  • provide an instance of MemResourceBase* to pointer manager constructor, along with boolean parameter that specifies if this memory resource should propagate when deserializing child objects. If no memory resource is provided, then MemResourceNewDelete is used, which calls ::operator new(bytes) and ::operator delete(ptr).

IMPORTANT: there are few things that you should know to correctly use custom allocations with StdSmartPtr:

  • Memory resource must live as long as the last object, that was allocated with it (this is required by std::shared_ptr, custom deleter is provided, that will be able to deallocate correctly when a shared pointer is destroyed).
  • std::unique_ptr acts differently with resources that it owns, depending on what deleter is used.
    • if default deleter is used, then a pointer is released and deallocated using provided memory resource.
    • if custom deleter is used, then a pointer is deallocated using this custom deleter.