
Akim Demaille <akim <at> lrde.epita.fr> writes:
Which is ok. However, I tried to do the same thing this time on top of Flyweight, using key_value, but failed miserably: the result is not made unique:
[...]
struct make_num : boost::noncopyable { make_num(int n) : res(std::make_shared<Num_impl>(n)) {}
Num res; operator Num() const { return res; } };
public: static Num make(int v) { using flyweight = boost::flyweight<boost::flyweights::key_value<int,make_num>>; return flyweight(v).get(); }
This is what's hapenning: 1. make(v) creates a *temporary* flyweight(v), which contains a make_num struct containing a std::shared_ptr<Num_impl>. 2. make(v) returns a copy of the shaered_ptr, which gets then a ref count of 2. 3. when make(v) exists, the temporary flyweight is destroyed, and as *there's no other flyweight with the same value*, the associated make_num struct gets erased from the flyweight internal factory. 4. Erasing the make_num results in its shared_ptr member being destroyed, hence the referenced to Num_impl gets a ref count of 1: it is not destroyed, this is why ~Num_impl is not invoked. 5. Next time you call make(v), there's no longer an equivalent value in the factoty, 1-4 are repeated and make(v) returns a shared_ptr to a *different* Num_impl. In short: what keeps a value around in a flyweight factory is the *flyweight* ref count, *not* the *shared_ptr* ref count of one of its members. Why do you want to have a factory per node type? Hash containers' performance is basically independent of the number of elements being contained, so you won't get any significant speedup by separating types --what's more, you can even get a performance reduction due to CPU cache misses, since having more hashed containers around places more bucket arrays in the program's working memory. Joaquín M López Muñoz Telefónica