当先锋百科网

首页 1 2 3 4 5 6 7

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