在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。这种计数应用十分广泛,比如java和C#等支持垃圾回收机制的语言编译器实现,COM组件的维护(com组件将维护一个称作是引用计数的数值。当客户从组件取得一个接口时,此引用计数值将增1。当客户使用完某个接口后,组件的引用计数值将减1.当引用计数值为0时,组件即可将自己从内存中删除),操作系统资源的管理等。
C++语言不支持垃圾回收机制,但是可以通过使用引用计数来模拟垃圾回收机制,也可以通过应用计数来管理“大数据类”(拷贝负值构造出新对象,代价较大),这样可以提高性能。实际上,引用计数并不总是性能获益者,引用计数、执行速度和资源约束是一种相互关系,这个需要程序员综合评估。
本文下面给出的代码是《C++沉思录》中的一个典型例子,个人觉得对于理解引用计数十分典型,虽然可能用引用计数显得不是特别必要,毕竟对象复制构造拷贝代价不是特别大,除非“表达式特别复杂”。其中,为了测试引用计数的析构函数是否在引用计数为0时释放,在DEBUG版本下面会显示析构情况。
#ifndef __EXPR__H__
#define __EXPR__H__
#include <iostream>
#include <string>
namespace smy
{
class Expr
{
// 内部类
class Expr_node
{
friend std::ostream& operator<<(std::ostream&, const Expr&);
friend std::ostream& operator<<(std::ostream& o, const Expr::Expr_node& e);
friend class Expr;
int use;
protected:
Expr_node()
: use(1) {}
virtual void print(std::ostream&) const = 0;
virtual int eval() const = 0;
virtual ~Expr_node()
{
#ifdef _DEBUG
std::cout << "Expr_node::~Expr_node()" << std::endl;
#endif
}
};
// 整数
class Int_node
: public Expr_node
{
friend class Expr;
int n;
protected:
Int_node(int k)
: n(k) {}
void print(std::ostream& o) const { o << n; }
int eval() const { return n; }
~Int_node()
{
#ifdef _DEBUG
std::cout << "Int_node::~Int_node() " << *this << std::endl;
#endif
}
};
// 单目运算符
class Unary_node
: public Expr_node
{
friend class Expr;
std::string op;
Expr_node* opnd;
protected:
Unary_node(const std::string& a, Expr_node* b)
: op(a), opnd(b) { opnd->use++; }
void print(std::ostream& o) const { o << "(" << op << *opnd << ")"; }
int eval() const
{
if (op == "-")
return -opnd->eval();
throw "error, bad op!";
}
~Unary_node()
{
#ifdef _DEBUG
std::cout << "Unary_node::~Unary_node() " << *this << std::endl;
#endif
if (--opnd->use == 0)
delete opnd;
}
};
// 双目运算符
class Binary_node
: public Expr_node
{
friend class Expr;
std::string op;
Expr_node* left;
Expr_node* right;
protected:
Binary_node(const std::string& a, Expr_node* b, Expr_node* c)
: op(a), left(b), right(c) { b->use++; c->use++; }
void print(std::ostream& o) const { o << "(" << *left << op << *right << ")"; }
int eval() const
{
int op1 = left->eval();
int op2 = right->eval();
if (op == "-")
return op1 - op2;
else if (op == "+")
return op1 + op2;
else if (op == "*")
return op1 * op2;
else if (op == "/")
{
if (op2 == 0)
throw "error, bad /0!";
return op1 / op2;
}
else if (op == "%")
{
if (op2 == 0)
throw "error, bad %0!";
return op1 % op2;
}
else
throw "error, bad op!";
}
~Binary_node()
{
#ifdef _DEBUG
std::cout << "Binary_node::~Binary_node() " << *this << std::endl;
#endif
if (--left->use == 0)
delete left;
if (--right->use == 0)
delete right;
}
};
public:
Expr(int n)
: p(new Int_node(n)) {}
Expr(const std::string& op, const Expr& t)
: p(new Unary_node(op, t.p)) {}
Expr(const std::string& op, const Expr& tl, const Expr& tr)
: p(new Binary_node(op, tl.p, tr.p)) {}
Expr(const Expr& t)
: p(t.p) { p->use++; }
Expr& operator=(const Expr&);
int eval() const { return p->eval(); }
~Expr()
{
if (--p->use == 0)
delete p;
}
private:
friend std::ostream& operator<<(std::ostream&, const Expr&);
friend std::ostream& operator<<(std::ostream& o, const Expr::Expr_node& e);
Expr_node* p;
};
std::ostream& operator<<(std::ostream& o, const Expr::Expr_node& e)
{
e.print(o);
return o;
}
std::ostream& operator<<(std::ostream& o, const Expr& e)
{
e.p->print(o);
return o;
}
Expr& Expr::operator=(const Expr& t)
{
t.p->use++;
if (--p->use == 0)
delete p;
p = t.p;
return *this;
}
} // end of namespace smy
#endif // end of expr.h
测试的主函数和运行结果如下
#include "stdafx.h"
#include "Expr.h"
using namespace smy;
int _tmain(int argc, _TCHAR* argv[])
{
Expr t1("*", Expr("-", 3, 4), Expr("+", 5, 6));
std::cout << t1 << "=" << t1.eval() << std::endl;
Expr t2("+", t1, t1);
std::cout << t2 << "=" << t2.eval() << std::endl;
Expr t3("/", t2, 4);
std::cout << t3 << "=" << t3.eval() << std::endl;
Expr t4("%", t3, 3);
std::cout << t4 << "=" << t4.eval() << std::endl;
return 0;
}
运行结构截图如下: