C++中的引用计数

5 c++ reference counting

我正在用C++实现一个数学库.该库将被编译为DLL,因此使用它的人只需要类的定义的头文件.

我班级的用户将是不熟悉该语言的人.但是,有些对象可能会在程序的几个部分中被引用.由于我不指望他们做内存管理,我想自己做.因此,我必须实现引用计数(垃圾收集不可能).

我想让那个引用计数尽可能透明,例如......

// Define a Bézier curve
CVecList pts;
pts.Add(Vector(0,0,0));
pts.Add(Vector(0,0,100));
pts.Add(Vector(0,100,0));
pts.Add(Vector(0,100,100));
CCurve* c1 = new CBezier(pts);

// Define a 3rd order B-Spline curve
pts.Clear();
pts.Add(Vector(0,0,0));
pts.Add(Vector(0,200,100));
pts.Add(Vector(0,200,200));
pts.Add(Vector(0,-200,100));
pts.Add(Vector(0,-200,200));
pts.Add(Vector(0,0,0));
CCurve* c2 = new CBSpline(pts,3);

// The Bézier curve object must be deleted automatically
// because the only reference to it has been released
// Similar to IUnknown::Release() in COM
c1 = c2;
Run Code Online (Sandbox Code Playgroud)

当我定义表面对象时,事情变得有点棘手,因为一些表面是根据两条曲线定义的:

CVecList pts;
// ...
CCurve* f = new CBezier(pts);

pts.Clear();
// ...
CCurve* g = new CBezier(pts);

// Mixed surface: S(u,v) = (1-v)*f(u) + v*g(u)
CSurface* s = new CMixed(f,g);

// There are two references to the first Bézier curve,
// the first one is f
// the second one is hidden in a member of CMixed

// Something similar applies to the second Bézier curve
Run Code Online (Sandbox Code Playgroud)

我认为重写operator =指针可能会有所帮助:

// This is what I tried, but it's illegal:
typedef CReferenceCounted* PRC;
PRC& operator =(PRC& dest, PRC& source)
{
    if (source)
        source->AddRef();
    if (dest)
        dest->Release();
    memcpy(&dest,&source,sizeof(PRC));
    return dest;
}
Run Code Online (Sandbox Code Playgroud)

...但后来我发现operator =除非它是一个类的非静态成员,否则它是无效的.

有人可以帮助我吗?

Joh*_*itb 11

你试过的是为标量类型重载运算符.除了枚举之外,C++不允许你这样做(除了operator =必须是成员之外).至少一种类型必须是用户定义的类型.因此,您要做的是将原始指针包装到用户定义的类中,该类重载构造函数,复制构造函数,复制赋值运算符和析构函数以及正确的引用计数.这是一个理想的情况boost::shared_ptr,它正是这样做的:

boost::shared_ptr<CCurve> c1(new CBezier(pts));
Run Code Online (Sandbox Code Playgroud)

表面处理相同:

CVecList pts;
// ...
boost::shared_ptr<CCurve> f(new CBezier(pts));

pts.Clear();
// ...
boost::shared_ptr<CCurve> g(new CBezier(pts));

// Mixed surface: S(u,v) = (1-v)f(u) + vg(u)
boost::shared_ptr<CSurface> s(new CMixed(f,g)); 
Run Code Online (Sandbox Code Playgroud)

继续使用该智能指针,它将自动管理指向对象的生命周期:如果指针的最后一个副本超出范围,则指向的对象被释放.shared_ptr设计易于使用.尽量避免使用原始指针.看看那些智能指针,它们将使您的程序员能够轻松使用C++ :)

编辑:如果要打包shared_ptr,可以使用pimpl(句柄/正文)习语:

/* ---- wrapper in header file bezier.hpp */

struct CBezier {
    CBezier(CVecList const& list);
    void do_calc();
    // ...

private:
    struct CBezierImpl;
    boost::shared_ptr<CBezierImpl> p;
};

/* ---- implementation file bezier.cpp */

// private implementation
struct CBezier::CBezierImpl {
    CBezierImpl(CVecList const& list);
    void do_calc();
    // ...
};


CBezier::CBezier(CVecList const& list)
:p(new CBezierImpl(list)) {

}

void CBezier::do_calc() {
    // delegate to pimpl
    p->do_calc();
}

// ...
Run Code Online (Sandbox Code Playgroud)