1#include <map> 2 3#include <boost/bind.hpp> 4#include <boost/enable_shared_from_this.hpp> 5#include <boost/shared_ptr.hpp> 6#include <boost/weak_ptr.hpp> 7 8#include "../Mutex.h" 9 10#include <assert.h> 11#include <stdio.h> 12 13using std::string; 14 15class Stock : boost::noncopyable 16{ 17 public: 18 Stock(const string& name) 19 : name_(name) 20 { 21 printf(" Stock[%p] %s\n", this, name_.c_str()); 22 } 23 24 ~Stock() 25 { 26 printf("~Stock[%p] %s\n", this, name_.c_str()); 27 } 28 29 const string& key() const { return name_; } 30 31 private: 32 string name_; 33}; 34 35namespace version1 36{ 37 38// questionable code 39class StockFactory : boost::noncopyable 40{ 41 public: 42 43 boost::shared_ptr<Stock> get(const string& key) 44 { 45 muduo::MutexLockGuard lock(mutex_); 46 boost::shared_ptr<Stock>& pStock = stocks_[key]; 47 if (!pStock) 48 { 49 pStock.reset(new Stock(key)); 50 } 51 return pStock; 52 } 53 54 55 private: 56 mutable muduo::MutexLock mutex_; 57 std::map<string, boost::shared_ptr<Stock> > stocks_; 58}; 59 60} 61 62namespace version2 63{ 64 65class StockFactory : boost::noncopyable 66{ 67 public: 68 boost::shared_ptr<Stock> get(const string& key) 69 { 70 boost::shared_ptr<Stock> pStock; 71 muduo::MutexLockGuard lock(mutex_); 72 boost::weak_ptr<Stock>& wkStock = stocks_[key]; 73 pStock = wkStock.lock(); 74 if (!pStock) 75 { 76 pStock.reset(new Stock(key)); 77 wkStock = pStock; 78 } 79 return pStock; 80 } 81 82 private: 83 mutable muduo::MutexLock mutex_; 84 std::map<string, boost::weak_ptr<Stock> > stocks_; 85}; 86 87} 88 89namespace version3 90{ 91 92class StockFactory : boost::noncopyable 93{ 94 public: 95 96 boost::shared_ptr<Stock> get(const string& key) 97 { 98 boost::shared_ptr<Stock> pStock; 99 muduo::MutexLockGuard lock(mutex_); 100 boost::weak_ptr<Stock>& wkStock = stocks_[key]; 101 pStock = wkStock.lock(); 102 if (!pStock) 103 { 104 pStock.reset(new Stock(key), 105 boost::bind(&StockFactory::deleteStock, this, _1)); 106 wkStock = pStock; 107 } 108 return pStock; 109 } 110 111 private: 112 113 void deleteStock(Stock* stock) 114 { 115 printf("deleteStock[%p]\n", stock); 116 if (stock) 117 { 118 muduo::MutexLockGuard lock(mutex_); 119 stocks_.erase(stock->key()); // This is wrong, see removeStock below for correct implementation. 120 } 121 delete stock; // sorry, I lied 122 } 123 mutable muduo::MutexLock mutex_; 124 std::map<string, boost::weak_ptr<Stock> > stocks_; 125}; 126 127} 128 129namespace version4 130{ 131 132class StockFactory : public boost::enable_shared_from_this<StockFactory>, 133 boost::noncopyable 134{ 135 public: 136 137 boost::shared_ptr<Stock> get(const string& key) 138 { 139 boost::shared_ptr<Stock> pStock; 140 muduo::MutexLockGuard lock(mutex_); 141 boost::weak_ptr<Stock>& wkStock = stocks_[key]; 142 pStock = wkStock.lock(); 143 if (!pStock) 144 { 145 pStock.reset(new Stock(key), 146 boost::bind(&StockFactory::deleteStock, 147 shared_from_this(), 148 _1)); 149 wkStock = pStock; 150 } 151 return pStock; 152 } 153 154 private: 155 156 void deleteStock(Stock* stock) 157 { 158 printf("deleteStock[%p]\n", stock); 159 if (stock) 160 { 161 muduo::MutexLockGuard lock(mutex_); 162 stocks_.erase(stock->key()); // This is wrong, see removeStock below for correct implementation. 163 } 164 delete stock; // sorry, I lied 165 } 166 mutable muduo::MutexLock mutex_; 167 std::map<string, boost::weak_ptr<Stock> > stocks_; 168}; 169 170} 171 172class StockFactory : public boost::enable_shared_from_this<StockFactory>, 173 boost::noncopyable 174{ 175 public: 176 boost::shared_ptr<Stock> get(const string& key) 177 { 178 boost::shared_ptr<Stock> pStock; 179 muduo::MutexLockGuard lock(mutex_); 180 boost::weak_ptr<Stock>& wkStock = stocks_[key]; 181 pStock = wkStock.lock(); 182 if (!pStock) 183 { 184 pStock.reset(new Stock(key), 185 boost::bind(&StockFactory::weakDeleteCallback, 186 boost::weak_ptr<StockFactory>(shared_from_this()), 187 _1)); 188 wkStock = pStock; 189 } 190 return pStock; 191 } 192 193 private: 194 static void weakDeleteCallback(const boost::weak_ptr<StockFactory>& wkFactory, 195 Stock* stock) 196 { 197 printf("weakDeleteStock[%p]\n", stock); 198 boost::shared_ptr<StockFactory> factory(wkFactory.lock()); 199 if (factory) 200 { 201 factory->removeStock(stock); 202 } 203 else 204 { 205 printf("factory died.\n"); 206 } 207 delete stock; // sorry, I lied 208 } 209 210 void removeStock(Stock* stock) 211 { 212 if (stock) 213 { 214 muduo::MutexLockGuard lock(mutex_); 215 auto it = stocks_.find(stock->key()); 216 if (it != stocks_.end() && it->second.expired()) 217 { 218 stocks_.erase(stock->key()); 219 } 220 } 221 } 222 223 private: 224 mutable muduo::MutexLock mutex_; 225 std::map<string, boost::weak_ptr<Stock> > stocks_; 226}; 227 228void testLongLifeFactory() 229{ 230 boost::shared_ptr<StockFactory> factory(new StockFactory); 231 { 232 boost::shared_ptr<Stock> stock = factory->get("NYSE:IBM"); 233 boost::shared_ptr<Stock> stock2 = factory->get("NYSE:IBM"); 234 assert(stock == stock2); 235 // stock destructs here 236 } 237 // factory destructs here 238} 239 240void testShortLifeFactory() 241{ 242 boost::shared_ptr<Stock> stock; 243 { 244 boost::shared_ptr<StockFactory> factory(new StockFactory); 245 stock = factory->get("NYSE:IBM"); 246 boost::shared_ptr<Stock> stock2 = factory->get("NYSE:IBM"); 247 assert(stock == stock2); 248 // factory destructs here 249 } 250 // stock destructs here 251} 252 253int main() 254{ 255 version1::StockFactory sf1; 256 version2::StockFactory sf2; 257 version3::StockFactory sf3; 258 boost::shared_ptr<version3::StockFactory> sf4(new version3::StockFactory); 259 boost::shared_ptr<StockFactory> sf5(new StockFactory); 260 261 { 262 boost::shared_ptr<Stock> s1 = sf1.get("stock1"); 263 } 264 265 { 266 boost::shared_ptr<Stock> s2 = sf2.get("stock2"); 267 } 268 269 { 270 boost::shared_ptr<Stock> s3 = sf3.get("stock3"); 271 } 272 273 { 274 boost::shared_ptr<Stock> s4 = sf4->get("stock4"); 275 } 276 277 { 278 boost::shared_ptr<Stock> s5 = sf5->get("stock5"); 279 } 280 281 testLongLifeFactory(); 282 testShortLifeFactory(); 283} 284