C++如何使用简单的引用计数
来源:互联网 发布:匪萌十月网络班 编辑:程序博客网 时间:2024/05/05 01:32
若你需要的只是分发指向同一个对象的多个指针,并且当最后一个指针消失的时候自动释放该对象的能力的话,你可以使用以下的类似“智能指针”的类。
代码如下:
// Fred.hclass FredPtr;class Fred {public: Fred() : count_(0) { } // 所有的构造函数都要设置count_为0! private: friend FredPtr; // 友元类 unsigned count_; // count_必须被所有构造函数初始化 // count_就是指向this的FredPtr对象数目};class FredPtr {public: Fred* operator-> () { return p_; } Fred& operator* () { return *p_; } FredPtr(Fred* p) : p_(p) { ++p_->count; } // p不能为NULL ~FredPtr() { if (--p_->count_ == 0) delete p_; } FredPtr(const FredPtr& p) : p_(p.p_) { ++p_->count_; } FredPtr& operator= (const FredPtr& p) { // 不要改变这些语句的顺序 // 如此的顺序适当地处理了(自赋值) ++p.p_->count; if (--p_->count_ == 0) deleete p_; p_ = p.p_; return *this; } private: Fred* p_; // p_永远不为NULL};
当然,你也可以使用嵌套类,将FredPtr改为Fred::Ptr
引用计数可以由指针计数或引用计数完成,上方显示了如何使用指针语义进行引用计数,下方将展示如何使用引用语义进行引用计数。
基本思想是允许用户认为他们在复制Fred对象,而实际上真正的实现并不真正复制,直到一些用户试图修改隐含的Fred对象时才复制。
Fred::Data类装载了Fred类所有的数据。Fred::Data也有一个额外的成员count_,来管理引用计数。Fred类最后成了一个指向Fred::Data的“智能指针”(内部的)
class Fred {public: Fred(); // 默认构造函数 Fred(int i, int j); // 普通构造函数 Fred(const Fred& f); // 拷贝构造函数 ~Fred(); void sampleInspectorMethod() const; // this对象不会变 void sampleMutatorMethod(); // 会改变this()对象 //...private: class Data { public: Data(); Data(int i, int j); Data(const Data& d); // 由于只有Fred能访问Fred::Data对象 // 只要你愿意,你可以使得Fred::Data的数据为public // 但如果那样使你不爽,就把数据作为private // 还要用friend Fred,使Fred成为友元类 unsigned count_; // count_是指向this的Fred对象的数目 // count_必须被所有的构造函数初始化为1 // (从1开始是因为它被创建它的Fred对象所指) }; Data* data_; Fred::Data::Data() : count_(1) {} Fred::Data::Data(int i, int j) : count_(1) {} Fred::Data::Data(const Data& d) : count_(1) {} Fred::Fred() : data_(new Data()) {} Fred::Fred(int i, int j) : data_(new Data(i, j)) {} Fred::Fred(const Fred& f) : data_(f.data_) { ++data_->count_; } Fred& Fred::operator= (const Fred& f) { // 不要更改这些语句的顺序 // 如此的顺序恰当的处理了自赋值问题 ++f.data_->count_; if (--data_->count_ == 0) delete data_; data_ = f.data_; return *this; } Fred::~Fred() { if (--data_->count_ == 0) delete data_; } void Fred::sampleInspectorMethod() const { // 该方法承诺"const",不改变*data_中任何东西 // 除此之外,任何数据访问将简单地使用data_->.. } void Fred::sampleMutatorMethod() { // 该方法可能需要改变*data_中的数据 // 因此首先检查this是否唯一指向*data_ if (data_->count_ > 1) { Data* d = new Data(*data); -- data_->count_; data_ = d; } assert(data_->count_ == 1); // 现在改方法如常进行"data_->..."访问 }};
如果非常经常地调用 Fred 的默认构造函数,你可以为所有通过Fred::Fred()构造的Fred 共享一个公共的Fred::Data 对象来消除那些 new调用。为避免静态初始化顺序问题,该共享的 Fred::Data 对象在一个函数内“首次使用”时才创建。如下就是对以上的代码做的改变(注意,该共享的Fred::Data对象的析构函数永远不会被调用;如果这成问题的话,要么解决静态初始化顺序的问题,要么索性返回到如上描述的方法):
// 如果非常经常地调用 Fred 的默认构造函数,// 你可以为所有通过Fred::Fred()构造的Fred 共享一个公共的Fred::Data 对象来消除那些 new调用。// 为避免静态初始化顺序问题,该共享的 Fred::Data 对象在一个函数内“首次使用”时才创建。// 如下就是对以上的代码做的改变(注意,该共享的Fred::Data对象的析构函数永远不会被调用;// 如果这成问题的话,要么解决静态初始化顺序的问题,要么索性返回到如上描述的方法):class Fred {public: //..private: //.. static Data* defaultData();};Fred::Fred() : data_(defaultData()) { ++ data_->count_;}Fred::Data* Fred::defaultData() { static Data*p = NULL; if (p == NULL) { p = new Data(); ++ p->count_; // 确保它不为0 } return p;}
// 前一个FAQ给出了引用语义的引用计数策略,// 但迄今为止都针对单个类而不是分层次的类。// 本FAQ扩展之前的技术以允许为类层次提供引用计数。// 基本不同之处在于现在Fred::Data是类层次的根,着可能使得它有一些虚函数。// 注意 Fred 类本身仍然没有任何的虚函数。// 虚构造函数用法用来建立 Fred::Data 对象的拷贝。要选择创建哪个派生类,// 如下的示例代码使用了命名构造函数用法,但还有其它技术(构造函数中加一个switch语句等)。// 示例代码假设了两个派生类:Der1和Der2。派生类的方法并不查觉引用计数。class Fred {public: static Fred create1(const std::string& s, int i); static Fred create2(float x, float y); Fred(const Fred& f); Fred& operator= (const Fred& f); ~Fred(); void sampleInspectorMethod() const; // this对象不会被改变 void sampleMutatorMethod(); // 会改变this对象 private: class Data { public: Data() : count_(1) {} Data(const Data& d) : count_(1) {} // 不要拷贝'count_'成员 Data& operator= (const Data&) { return *this; } // 不要拷贝'count_'成员 virtual ~Data() { assert(count_== 0); } // 虚析构函数 virtual Data* clone() const = 0; // 虚构造函数 virtual void sampleInspectorMethod() const = 0; // 纯虚函数 virtual void sampleMutatorMethod() = 0; private: unsigned count_; // count_不需要是protected的 friend Fred; // 允许Fred访问count_ }; class Der1 : public Data { public: Der1(const std::string& s, int i); virtual void sampleInspectorMethod() const; virtual void sampleMutatorMethod(); virtual Data* clone() const; }; class Der2 : public Data { public: Der2(float x, float y); virtual void sampleInspectorMethod() const; virtual void sampleMutatorMethod(); virtual Data* clone() const; }; Fred(Data* data); // 创建一个拥有*data的Fred智能引用 // 它是private的以迫使用户使用createXXX()方法 // 要求:data必能为NULL Data* data_; // invariant: data_ is never NULL};Fred::Fred(Data* data) : data_(data) { assert(data != NULL); }Fred Fred::create1(const std::string& s, int i) { return Fred(new Der1(s, i)); }Fred Fred::create2(float x, float y) { return Fred(new Der2(x, y)); }Fred::Data* Fred::Der1::clone() const { return new Der1(*this); }Fred::Data* Fred::Der2::clone() const { return new Der2(*this); }Fred::Fred(const Fred& f) : data_(f.data_) { ++ data_->count_;}Fred& Fred::operator= (const Fred& f) { // 不要改变这些语句的顺序! // 如此的顺序适当地处理了自赋值问题 ++ f.data_->count_; if (--data->count_ == 0) delete data_; data_ = f.data_; return *this;}Fred::~Fred() { if (--data_->count_ == 0) delete data_;}void Fred::sampleInspectorMethod() const { // 该方法承诺"const", 不改变*data_中的任何东西 // 因此我们只要直接把方法传递给*data_ data_->sampleInspectorMethod();}void Fred::sampleMutatorMethod() { // 该方法可能需要改变*data_中的数据 // 因此首先检查this是否唯一指向*data_ if (data_->count_ > 1) { Data* d = data_->clone(); // 虚构造函数用法 -- data_->count_; data_ = d; } assert(data_->count_ == 1); // 现在直接把方法传递给*data_; data_->sampleInspectorMethod();}// 自然,Fred::Der1和Fred::Der2的构造函数和sampleXXX方法将需要被以某周途径适当的实现
- C++如何使用简单的引用计数
- 使用引用计数的类
- OC 内存管理 --- 引用计数简单使用
- 简单的模拟多线程引用计数原理
- 简单的模拟多线程引用计数原理
- Objective C 中NSNumber的引用计数
- Object-C 关于引用计数的说明
- objective-c 的引用计数管理
- objective-c 引用计数
- Effective c++:引用计数
- 【c++】引用计数
- Objective-C 引用计数
- 【C++】引用计数
- OC使用引用计数的内存管理
- 使用引用计数扩展c语言实现内存自动管理的思考 -- 为什么存在内存泄露
- Swift 引用计数总结 Strong,Weak, unowned 简单使用
- ANSI-C中使用引用计数(译)
- 通过引用计数解决野指针的问题(C&C++)
- Java IO 基本知识(2)
- Java IO 基本知识
- Java IO 基本知识
- ZBrush
- PeopleSoft Configuration Settings for Tracing
- C++如何使用简单的引用计数
- ArcEngine开发之打印地图(C#)
- 交换排序之冒泡排序
- java ---- 数学函数Math和随机产生数值Random
- Hdu 1010 Tempter of the Bone
- Code128 条码生成
- 初始化与赋值
- Windows socket 编程汇总
- Visual Studio 2010/2008(MSDN原版下载)