1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| // (c) Luc Hermitte, 2012, licence: BSL
#include <cassert>
#include <unordered_map>
#include <vector>
#include <functional>
#include <memory>
#include <string>
#include <iostream>
#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
# define HAS_RANGE_BASED_FOR
#endif
struct DeleterNotifier {
typedef std::function<void()> Listener_t;
typedef std::vector<Listener_t> ListenerList_t;
DeleterNotifier() {}
template <typename Holded_>
void operator()(Holded_ const* p) {
#if defined(HAS_RANGE_BASED_FOR)
for ( auto l : m_listeners) l();
#else
for (ListenerList_t::const_iterator b = m_listeners.begin(), e = m_listeners.end()
; b != e
; ++b
)
{
(*b)();
}
#endif
std::cout << "deleting " << *p << " present in " << m_listeners.size() << " maps\n";
delete p;
}
template <typename Listener_> void add_listener(Listener_ l_) {
m_listeners.push_back(l_);
}
private:
ListenerList_t m_listeners;
};
template <typename Key_, typename Holded_, typename PKey_>
void insert(
std::unordered_map<Key_, std::weak_ptr<Holded_>> & map_,
PKey_ const& key_,
std::shared_ptr<Holded_> & value_)
{
assert(value_);
const auto wh = map_.insert(std::make_pair(key_, value_));
DeleterNotifier * deleter = std::get_deleter<DeleterNotifier>(value_);
if (deleter) {
assert(deleter);
deleter->add_listener( [&]{
map_.erase(key_);
// map_.erase(wh.first); // insert invalidates unordered_map::iterator s
});
}
}
typedef std::unordered_map<std::string, std::weak_ptr<int>> Map;
typedef std::shared_ptr<int> sptr_t;
template <typename T, class... Args> std::shared_ptr<T> make_shared(Args&& ... args) {
return std::shared_ptr<T>(new T(args...), DeleterNotifier());
}
int main()
{
Map map1;
Map map2;
{
sptr_t sp0;
{
sptr_t sp1 = make_shared<int>(42);
sp0 = sp1;
insert(map1, ("toto"), sp1);
// Q: will this always impact sp0 deleter ?
// A: it seems so: §20.7.2.2.10/9,13,18,...
sptr_t sp2 = make_shared<int>(22);
insert(map1, ("titi"), sp2);
insert(map2, ("titi"), sp2);
std::cout << map1.size() << "\n";
std::cout << map2.size() << "\n";
}
std::cout << map1.size() << "\n";
std::cout << map2.size() << "\n";
}
std::cout << map1.size() << "\n";
std::cout << map2.size() << "\n";
return 0;
} |
Partager