pur*_*uck 35 c++ tr1 shared-ptr
我一直在考虑使用共享指针,我知道如何自己实现它 - 不想这样做,所以我在尝试std::tr1::shared_ptr,我有几个问题......
引用计数是如何实现的?它是否使用双向链表?(顺便说一句,我已经用Google搜索了,但我找不到任何可靠的东西.)
使用它有任何陷阱std::tr1::shared_ptr吗?
Emi*_*lia 55
shared_ptr 必须管理一个引用计数器和一个删除函数的携带,该函数由初始化时给出的对象类型推导出来.
所述shared_ptr类通常承载两个成员:一个T*(由返回operator->并在解除引用operator*)和一个aux*其中aux是包含内抽象类:
virtual destroy()=0;这样的aux类(实际名称取决于实现)是由一系列模板化类(由显式构造函数给出的类型参数化,比如U派生自派生T)派生的,它们添加:
T*与实际类型相同,但是需要这样才能正确管理作为派生层次结构中具有多个T的基础的所有情况)UTdeletor作为删除策略给出的对象的副本到显式构造函数(或者默认deletor只做删除p,上面p是哪里U*)简化的草图可以是这样的:
template<class T>
class shared_ptr
{
struct aux
{
unsigned count;
aux() :count(1) {}
virtual void destroy()=0;
virtual ~aux() {} //must be polymorphic
};
template<class U, class Deleter>
struct auximpl: public aux
{
U* p;
Deleter d;
auximpl(U* pu, Deleter x) :p(pu), d(x) {}
virtual void destroy() { d(p); }
};
template<class U>
struct default_deleter
{
void operator()(U* p) const { delete p; }
};
aux* pa;
T* pt;
void inc() { if(pa) interlocked_inc(pa->count); }
void dec()
{
if(pa && !interlocked_dec(pa->count))
{ pa->destroy(); delete pa; }
}
public:
shared_ptr() :pa(), pt() {}
template<class U, class Deleter>
shared_ptr(U* pu, Deleter d) :pa(new auximpl<U,Deleter>(pu,d)), pt(pu) {}
template<class U>
explicit shared_ptr(U* pu) :pa(new auximpl<U,default_deleter<U> >(pu,default_deleter<U>())), pt(pu) {}
shared_ptr(const shared_ptr& s) :pa(s.pa), pt(s.pt) { inc(); }
template<class U>
shared_ptr(const shared_ptr<U>& s) :pa(s.pa), pt(s.pt) { inc(); }
~shared_ptr() { dec(); }
shared_ptr& operator=(const shared_ptr& s)
{
if(this!=&s)
{
dec();
pa = s.pa; pt=s.pt;
inc();
}
return *this;
}
T* operator->() const { return pt; }
T& operator*() const { return *pt; }
};
Run Code Online (Sandbox Code Playgroud)
在weak_ptr需要互操作性的情况下,需要第二个计数器(weak_count)aux(将递增/递减weak_ptr),并且delete pa只有当两个计数器都达到零时才必须发生.
Zie*_*ezi 29
引用计数是如何实现的?
可以使用基于策略的类设计1将智能指针实现解构为:
存储政策
所有权政策
转换政策
检查政策
包含为模板参数.流行的所有权策略包括:深层复制,引用计数,引用链接和破坏性复制.
引用计数跟踪指向(拥有2)同一对象的智能指针的数量.当数字变为零时,删除指针对象3.实际的柜台可能是:
... [1] 依赖于观察,你并不真正需要指向一个指针对象的智能指针对象的实际数量; 你只需要检测该计数何时下降到零.这导致了保留"所有权列表"的想法:
参考链接优于引用计数的优点是前者不使用额外的免费存储,这使得它更可靠:创建引用链接的智能指针不会失败.缺点是引用链接需要更多的内存用于其簿记(三个指针与仅一个指针加一个整数).此外,引用计数应该更快一些 - 当您复制智能指针时,只需要间接和增量.列表管理稍微复杂一些.总之,只有在免费商店稀缺时才应使用引用链接.否则,更喜欢引用计数.
它(
std::shared_ptr)是否使用双向链表?
我在C++标准中找到的所有内容都是:
20.7.2.2.6 shared_ptr creation
...
7. [注意:这些函数通常会分配更多内存,而不是sizeof(T)允许内部簿记结构,例如引用计数. - 尾注]
在我看来,这不包括双重链表,因为它们不包含实际计数.
使用它有任何陷阱
std::shared_ptr吗?
计数或链接的参考管理是资源泄漏的受害者,称为循环引用.让对象A拥有一个指向对象B的智能指针.另外,对象B拥有一个指向A的智能指针.这两个对象形成一个循环引用; 即使你不再使用它们中的任何一个,它们也互相使用.参考管理策略无法检测此类循环引用,并且这两个对象将永远分配.
由于shared_ptr使用引用计数的实现,循环引用可能是一个问题.shared_ptr可以通过更改代码来中断循环链,以便其中一个引用是a weak_ptr.这是通过在共享指针和弱指针之间分配值来完成的,但弱指针不会影响引用计数.如果指向对象的唯一指针很弱,则该对象将被销毁.
1.每个设计功能,如果制定为策略,则具有多个实现.
2.智能指针类似于指向分配对象的指针,new不仅指向该对象,而且还负责其销毁以及释放它占用的内存.
3.没有其他问题,如果没有使用其他原始指针和/或指向它.
[1]现代C++设计:应用通用编程和设计模式.Andrei Alexandrescu,2001年2月1日
如果你想看到所有血淋淋的细节,你可以看看 boost 的shared_ptr实现:
https://github.com/boostorg/smart_ptr
引用计数似乎通常是通过计数器和平台特定的原子递增/递减指令或使用互斥锁进行显式锁定来实现的(请参阅详细命名空间atomic_count_*.hpp中的文件)。
| 归档时间: |
|
| 查看次数: |
27068 次 |
| 最近记录: |