HTTPS SSH
# Purpose `value_ptr` aims to provide a class similar to `unique_ptr`, but with copy semantics of the pointed-to object. This allows two things: 1. You can give an object that would otherwise be expensive to move cheap move semantics at the cost of an extra indirection, but otherwise remain unchanged. For instance, an application that stores many of a particular class in a container and needs to perform frequent sorting and insertions may find a `std::vector<value_ptr<T>>` to perform better than `std::vector<T>`, `std::list<T>`, or `std::deque<T>`. 2. You can treat an object like a value, but still use run-time polymorphism via virtual function calls. Unfortunately, C++ does not allow overloading `operator.` (the member access operator), so the syntax requires pointer syntax of `value->` rather than value syntax of `value.`, even though `value_ptr` models the latter. # Implementation / Design Decisions Wherever possible, `value_ptr` defers to `unique_ptr` in its implementation, and seeks only to concern itself with copy construction and copy assignment. The definition of a copy can be surprisingly challenging, however. For any type that isn't a class, the copy constructor / copy assignment operator of the static type will always be correct, because only classes can serve as a base of another type. However, for a class type, I can have a situation such as `value_ptr<base_type>`, where the static type is `base_type`, but it may actually be pointing to an object that is a `derived_type`. In this case, if I were to just use the copy constructor of `base_type`, I would 'slice' the object that I'm trying to copy. ## Cloning policy ### Other implementations #### member clone This situation has been solved in a few different ways. Some libraries that deal with copying polymorphically require the class to define a virtual `clone` member function in the base and all derived classes. This has one major drawback, however. * It requires the contained class to be modified to use it with the `value_ptr`. This can be impossible in the case that the pointed-to object comes from third-party code. Note that it does not require a virtual function. The usage of a virtual member function `clone` vs. a non-virtual member function `clone` is identical. A class that is not virtual and is not designed to be derived from can have a regular member function that just calls the copy constructor. #### Template function Other libraries use a template function that must be defined for the user's type. This is the approach used by the Boost.Pointer Container library. This neatly avoids the problem listed above, and allows for easy specialization of non-class types. The Boost Pointer Container library uses the function `new_clone`: However, the question remains of what the default behavior should be. Boost.Pointer Container chose to define a default copy for all types, which is to invoke the copy constructor of the static type. However, if you use it in such a way that it would cause a slice, there is a runtime error. TODO: Determine if there is a runtime error or a slice for the default implementation in the event that you try to copy a base class pointer that has no virtual member functions. ### This library's implementation One drawback with the `new_clone` approach is that you are defining cloning behavior on a per-type basis. This is correct for a majority of use cases (for instance, a polymorphic base that has a virtual clone member function should always be cloned used that member function), but it fails to support use cases that `std::unique_ptr` works with. The most straightforward example is interoperability with C functions. A user of `value_ptr` may wish to, in some cases, transfer ownership of the pointer to some C function. The only safe way to do this is to tell the `value_ptr` that in this case, the object should be allocated with `malloc` and deleted with `free`. However, the class owned by the `value_ptr` would probably still want default behavior of `new` and `delete`. Due to the above reasons, `value_ptr` has a template parameter that defines the cloning strategy, similar to how `std::unique_ptr` allows for custom deleters. A default definition is given for non-class types that performs a simple copy, and this definition can be expanded to class types by specializing `default_new`. One possible option for the future would be to use `std::allocator` rather than `default_new`. # Prior work ## Edd Dawson's value_ptr [http://www.mr-edd.co.uk/code/value_ptr] This class fails to follow the zero-overhead principle. `std::unique_ptr`'s guiding design was that it should have no run-time overhead in space or time compared to using a raw pointer. Dawson's `value_ptr` has virtual functions and two pointers of overhead. ## Martinho Fernandes's Wheels value_ptr [https://bitbucket.org/martinhofernandes/wheels/src/8a1366b0a195/include/wheels/smart_ptr/value_ptr.h%2B%2B?at=default] I found this when my `value_ptr` was nearly complete, and it is almost identical to my version, down to many implementation details. It appears to follow the no-overhead principle, and has a template parameter for the cloner and deleter. However, I believe my implementation to be slightly simpler, because my `value_ptr` defers to `std::unique_ptr` wherever possible, whereas Fernandes's `value_ptr` implements everything itself. However, there is a lot of good stuff in this version, and I expect that my value_ptr will be updated with some improvements that Fernandes has.