C ++中的引用计数 [英] Reference Counting in C++

查看:304
本文介绍了C ++中的引用计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C ++中实现了一个数学库。该库将被编译为一个DLL,所以那些使用它的人只需要头文件的类的定义。

I'm implementing a math library in C++. The library will be compiled to a DLL so those who use it will only need the header files the classes' definitions.

我的类的用户将是新的人到语言。但是,有一些对象可能在其程序的几个部分中引用。因为我不期望他们做内存管理,我想自己做。因此,我必须实现引用计数(垃圾收集不是一种可能性)。

The users of my classes will be people who are new to the language. However, there are some objects that might be referenced in several parts of their programs. Since I don't expect them to do the memory management, I'd like to do it myself. Therefore, I have to implement reference counting (garbage collection is not a possibility).

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

I want to make that reference counting as transparent as possible, for example...

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

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

Things get a little bit more tricky when I define surface objects, because some surfaces are defined in terms of two curves:

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

我认为重写 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;
}

...但我发现 operator = 除非作为类的非静态成员,否则无效。

... but then I found that operator = is not valid unless it is as a non-static member of a class.

任何人都可以帮助我吗?

Could anybody possible help me?

推荐答案

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

What you tried was to overload an operator for scalar types. C++ doesn't allow you to do that except for enumerations (beside the point that operator= has to be a member). At least one of the types has to be a user defined type. Thus, what you want to do is to wrap the raw pointer into a user defined class, which overloads constructor, copy constructor, copy assignment operator and destructor an do the proper reference counting. This is an ideal situation for boost::shared_ptr, which does exactly that :

boost::shared_ptr<CCurve> c1(new CBezier(pts));

与曲面相同的交易:

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

继承该智能指针,它将自动管理指向对象的生命周期:如果指针的最后一个副本超出范围,则指向的对象将被释放。 shared_ptr 旨在易于使用。尽量避免使用原始指针尽可能多。看看这些聪明的指针,他们会缓解你的程序员用C ++生活:)

Carry around that smart pointer, and it will automatically manage the life-time of the pointed to object: If the last copy of the pointer goes out of scope, the object pointed to is freed. shared_ptr is designed to be easy to use. Try to avoid working with raw pointers as much as you can. Have a look at those smart pointers, they will ease your programmers live with C++ :)

编辑:如果你要包装一个shared_ptr ,你可以使用pimpl(handle / body)idiom:

Edit: If you are going to wrap a shared_ptr, you can do so using the pimpl (handle/body) idiom:

/* ---- 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();
}

// ...

这篇关于C ++中的引用计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆