C ++中的引用计数 [英] Reference Counting in 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 $ c的理想情况$ c>
,正是这样:
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屋!