C++对象池
对象池含义
假设有Stock类,代表一只股票的价格,每一只股票有一个唯一的字符串表示。Stock是个主动对象,他不断获取新的价格。那么为了节省资源,同一个程序同一只股票应该只出现一次,如果股票没有被用到那么应该被析构。
需要的组件
enable_shared_from_this类
- C++11的新特性
- 该类提供的功能允许派生类的对象创建指向自己的shared_ptr实例,并与现有的shared_ptr对象共享所有权
boost::noncopyable类
- 阻止子类调用赋值和copy构造函数
- 作用:可以在写单例模式时保证全局唯一
weak_ptr智能指针
- 共享但不拥有某对象
- 当最后一个指向shared_ptr的指针释放,weak_ptr自动成空
弱回调
- 如果对象还活着,就调用它的成员函数,否则忽略之-弱回调
- 利用std::bind、std::shared_ptr、 std::weak_ptr 实现弱回调
要注意的问题
- 股票对象析构之后,容器大小要减一
- 引用计数为零后,容器内的股票对象要析构
- 以及在代码中注释的问题
- 这个StockFactory只针对单个Stock,如要遍历Stock容易死锁,这时需要将遍历容器的读写操作分离,也就是对于读操作可以复制一份容器并加锁,对于写操作要判有没有其他操作,如果有就复制一份并加锁,没有就只加锁不复制
代码
#ifndef STOCK_H
#define STOCK_H
#include <string>
class Stock
{
private:
//股票名字
std::string name_;
//股票价格
uint32_t price_;
public:
Stock(std::string key){
name_ = key;
price_ = 0;
}
virtual ~Stock(){
}
std::string key(){
return name_;
}
};
#endif /* STOCK_H */
#ifndef STOCKFACTORY_H
#define STOCKFACTORY_H
#include <boost/noncopyable.hpp>
#include <map>
#include <memory>
#include <mutex>
#include <functional>
#include <iostream>
#include "stock.h"
class StockFactory : public std::enable_shared_from_this<StockFactory>, boost::noncopyable
{
public:
std::shared_ptr<Stock> get(const std::string& key);
StockFactory() {}
virtual ~StockFactory() {}
private:
static void weakDeleteCallback(const std::weak_ptr<StockFactory>& wkFactory, Stock* stock);
void removeStock(Stock* stock);
private:
std::mutex mutex_;
//map中保存weak_ptr,外部引用计数为零是自动销毁
//如果保存shared_ptr,则不会自动销毁
std::map<std::string, std::weak_ptr<Stock>> stocks_;
};
std::shared_ptr<Stock> StockFactory::get(const std::string& key)
{
std::shared_ptr<Stock> pStock;
std::lock_guard<std::mutex> lock(mutex_);
std::weak_ptr<Stock>& wkStock = stocks_[key];
//weak_ptr提升为shared_ptr,如果失败会返回空
pStock = wkStock.lock();
//如果返回空,则表示股票不存在,那么创建之
if(!pStock) {
//reset函数在shared_ptr销毁时做清理工作
pStock.reset(new Stock(key),
bind(&StockFactory::weakDeleteCallback,
//将shared_ptr转化为weak_ptr,使得工厂函数生命正常结束,不会延长至调用bind
//在weakDeleteCallback中不会发生二次析构
//避免使用this,容易成为野指针
std::weak_ptr<StockFactory>(shared_from_this()),
std::placeholders::_1)
);
wkStock = pStock;
}
//给外部使用shared_ptr,外部shared_ptr销毁,内部weak_ptr也会销毁
return pStock;
}
void StockFactory::weakDeleteCallback(const std::weak_ptr<StockFactory>& wkFactory, Stock* stock)
{
std::shared_ptr<StockFactory> factory(wkFactory.lock());//尝试提升
if(factory) {
factory->removeStock(stock);
}
//析构股票对象
delete stock;
}
void StockFactory::removeStock(Stock* stock)
{
if(stock) {
std::lock_guard<std::mutex> lock(mutex_);
stocks_.erase(stock->key());
}
}
#endif /* STOCKFACTORY_H */
/*test.cpp*/
#include <cassert>
#include <iostream>
#include "stockfactory.h"
int main()
{
std::shared_ptr<StockFactory> factory(new StockFactory);
std::shared_ptr<Stock> stock1 = factory->get("BAT");
std::shared_ptr<Stock> stock2 = factory->get("BAT");
assert(stock1 == stock2);
return 0;
}