Message: 7 Date: Mon, 20 Apr 2015 18:39:57 +0000 (UTC) From: Joaquin M Lopez Munoz <joaquin@tid.es> To: boost@lists.boost.org Subject: Re: [boost] [ValueRef] Message-ID: <loom.20150420T202848-660@post.gmane.org> Content-Type: text/plain; charset=utf-8
THOMAS JORDAN <tomjordan766 <at> gmail.com> writes:
From: Andrey Semashev <andrey.semashev <at> gmail.com>
Is this similar to Boost.Flyweight?
It is similar in that both provide a 'smart' handle which can be used pretty much as a drop in for the wrapped type.
However, Boost.Flyweight requires the wrapped type to be hashable.
Not necessarily; set_factory, for instance, requires values to be less-than comparable:
http://boost.org/libs/flyweight/doc/tutorial/configuration.html#set_factory Ok
Also, see below.
Also, there is a level of indirection with Flyweight which can mean that unnecessary temps may need to be created to do the initial lookup (and addition) to the Flyweight store, unless you use the Flyweight key-map interface.
Boost.Flyweight uses move semantics and perfect fwd ction where available, I don't see how another solution can do better on this front
Agreed, I'll withdraw that statement. However, as I said in the O.P., the ValueRef implementation I have done is currently only C++03. It uses a combination of N x forwarding constructor overloads taking arguments by const reference, and the client can use reference wrappers to forward to lvaluesto do the non-perfect forwarding (as boost.shared_ptr make_shared does) . The intention in the final library would be to support C++11/perfect forwarding and possibly Boost.Move for C++03 move semantics. So they would be equivalent in that regard.
ValueRef does not use 'flyweighting.' That is, if there are two ValueRefs created independently with the same value, e.g.,
ValueRef<std::vector<int> > v1(10,10), v2(10,10);
there will be two separate wrapped vector<int> objects - it is only when copying/assigning that sharing takes place. It is simpler than Flyweight and is essentially intended to be a more value-orientated option to shared-ptr-to-const.
The lib is extensible to the point that ValueRef can potentially be built on top of it:
template<typename Entry,typename Key> struct ValueRefFactory { using handle_type=Entry*;
template <typename E> handle_type insert(E&& x){return new Entry{std::forward<E>(x)};} void erase(handle_type h){delete h;} const Entry& entry(handle_type h){return *h;} };
template<typename T> using ValueRefImpl=flyweight< T,no_locking, factory<ValueRefFactory<boost::mpl::_1,boost::mpl::_2>>>;
template<typename T> struct ValueRef:ValueRefImpl<T> { using impl_type=ValueRefImpl<T>; const impl_type& impl()const{return *this;} using impl_type::impl_type; ValueRef(const ValueRef&x):impl_type(x.impl()){} ValueRef(ValueRef&x):impl_type(x.impl()){} ValueRef(const ValueRef&&x):impl_type(x.impl()){} ValueRef(ValueRef&&x):impl_type(x.impl()){} using impl_type::operator=; const T& operator*()const{return this->get();} const T* operator->()const{return &this->get();} bool identity(const ValueRef& x)const{return &**this==&*x;} };
See complete example at:
(except the unique_instance bit, which can be done, but admittedly with more effort).
Another (less significant) difference is that ValueRef currently has no dependency on MPL, which I believe Flyweight does, though that could well change if needed.
Boost.Flyweight is indeed heavier on the include side than some people might be comfortable with.
I think this is my concern with having Boost Flyweight as the only option for what is a relatively simple type. ValueRef is currently about 350 lines of easy-to-understand code in a single header file, and has no dependencies on MPL or any other Boost or std libraries, with the exception of an atomic library. It is intended in particular as a lightweight, clean replacement for shared-ptr-to-const, which I see used a lot in code. I also unfortunately y see shared-ptr-to-non-const being used a lot when people should be using shared-ptr-to-const, which is less safe and makes it much harder to reason about what is going on. ValueRef is an explict, consistent and safe alternative to such (mis)usages, and would also sit more comfortably with people who have concerns about build times, library-dependencies and cross-platform issues, etc.
Joaqu?n M L?pez Mu?oz Telef?nica
Tom.