Boost logo

Boost Users :

Subject: Re: [Boost-users] Flyweight: wrapping shared_ptr
From: Akim Demaille (akim_at_[hidden])
Date: 2014-10-09 11:29:02


Le 9 oct. 2014 à 12:35, Joaquin M Lopez Munoz <joaquin_at_[hidden]> a écrit :

> I think you forgot to add that support in some of poly_older ctors
> and assignment operators:
>
> poly_holder(const poly_holder& x);
> poly_holder& operator=(const poly_holder& x);
> poly_holder& operator=(poly_holder&& x);

Yes, thanks.

I wanted to try another approach: one factory per node type.
Here is a version that seems to work, but does not use Boost.Flyweight
at all. Instead each node type maintains the factory as a plain
std::map<tuple<Arguments>, weak_ptr<Value>>. This is a weak_ptr
otherwise if I store shared_ptr, then of course the values are kept
alive by the factory itself.

This is the result:

http://coliru.stacked-crooked.com/a/28bb07a0b0e59fbb

For instance Bin reads:

struct Bin_impl;
using Bin = std::shared_ptr<Bin_impl>;

struct Bin_impl: Exp_impl
{
  // cannot make it private: we need friendship with
  // std::make_shared<Bin_impl>'s internal details, which seems
  // impossible to spell out portably.
  Bin_impl(char o, Exp lhs, Exp rhs)
    : op(o)
    , l(lhs)
    , r(rhs)
  {}

public:
  ~Bin_impl()
  {}

  static Bin make(char o, Exp lhs, Exp rhs)
  {
    static std::map<std::tuple<char, Exp, Exp>, std::weak_ptr<Bin_impl>> map_;
    auto k = std::make_tuple(o, lhs, rhs);
    auto i = map_.find(k);
    if (i == end(map_) || i->second.expired())
      {
        auto res = std::make_shared<Bin_impl>(o, lhs, rhs);
        map_.emplace(k, res);
        return res;
      }
    else
      return Bin(i->second);
  }
...

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:

http://coliru.stacked-crooked.com/a/2b768fa26574adea

I tried this way:

struct Num_impl;
using Num = std::shared_ptr<const Num_impl>;
std::ostream& operator<<(std::ostream& o, const Num_impl& b);

struct Num_impl
{
  //private:
  Num_impl(int v)
    : val(v)
  {
    std::cerr << '!' << *this << '\n';
  }

  ~Num_impl()
  {
    std::cerr << "~" << *this << '\n';
  }

  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();
  }

  std::ostream& print(std::ostream& o) const
  {
    return o << val;
  }

  int val = 0;
};

I suppose that it's a bad idea for Num::make to return the
result of the call to get(), as this prevents the flyweight
from tracking the values. Yet the destructor was not called,
so I don't understand why Flyweight fails to see the duplicate
42.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net