在过去的几年里,我普遍认为
如果我要使用参考计数的智能指针
侵入性智能指针是可行的方法。
--
但是,由于以下原因,我开始喜欢非侵入性智能指针:
这个Foo在非侵入性智能指针中移动对象比入侵智能指针更容易的唯一原因是:
在非侵入式智能指针中,只有一个指针指向每个Foo.
在入侵智能指针中,我不知道每个Foo指向多少个对象。
现在,非侵入性智能指针的唯一成本.是双重间接。也许这搞砸了暗藏室。
有没有人能很好地研究这一额外的间接方向是昂贵的?
编辑:通过智能指针,我可能指的是其他人所说的“共享-指针”;整个想法是:有一个引用计数附加到对象,当它点击0时,该对象将自动删除。
发布于 2010-03-21 10:01:01
侵入性指针和非侵入性指针之间有几个重要区别:
第二(非侵入性)的最大优势是:
shared_ptr/weak_ptr)的弱引用要简单得多。第一个优点是当您需要获得智能指针时(至少在boost::shared_ptr、std::tr1::shared_ptr的情况下)。
shared_ptr。发布于 2010-03-21 13:50:27
首先,我要提醒您,共享所有权通常是一种难以驯服的野兽,并且可能导致很难根除bug。
有许多方法可以避免共享所有权。Factory方法(使用Boost指针容器实现自身)是我个人最喜欢的方法之一。
现在,关于参考点票.
1.侵入性指针
计数器嵌入在对象本身中,这意味着:
weak_ptr,所以如果不使用Observer模式,您就不能在设计中有循环的引用。相当复杂2.非侵入性指针
我只谈boost::shared_ptr和boost::weak_ptr。最近,我对源代码进行了一些深入的研究,以精确地了解机械原理,而且确实有更复杂的事情要比上面的更复杂!
// extract of <boost/shared_ptr.hpp>
template <class T>
class shared_ptr
{
T * px; // contained pointer
boost::detail::shared_count pn; // reference counter
};weak_ptr。shared_ptr对象的对象需要了解对象析构函数(参见示例)下面是一个小小的例子,来说明这个向前声明的魔力:
// foofwd.h
#include <boost/shared_ptr.hpp>
class Foo;
typedef boost::shared_ptr<Foo> foo_ptr;
foo_ptr make_foo();
// foo.h
#include "foofwd.h"
class Foo { /** **/ };
// foo.cpp
#include "foo.h"
foo_ptr make_foo() { return foo_ptr(new Foo()); }
// main.cpp
#include "foofwd.h"
int main(int argc, char* argv[])
{
foo_ptr p = make_foo();
} // p.get() is properly released有一点模板魔术来授权这一点。基本上,计数器对象嵌入了一个允许进行某种类型擦除的disposer* (但是是第三个分配)。但是非常有用,因为它确实允许转发声明!
3.结论
虽然我同意侵入性指针可能更快,因为在较少的分配中(为shared_ptr分配了3个不同的内存块),但也没有那么实用。
因此,我想向您指出Boost侵入指针库,特别是它的介绍:
通常情况下,如果
intrusive_ptr是否比shared_ptr更适合您的需求并不明显,那么首先尝试shared_ptr-based设计。
发布于 2010-03-21 09:47:24
我不知道一项关于非侵入性过度侵入造成的额外成本的研究。但我要指出的是,非侵入性似乎是C++专家普遍推荐的.当然,这可能没什么意义!但理由很合理:如果你需要智能指针,那是因为你想要一种更简单的方法来实现对象生命周期管理,而不是手工编写它,所以你强调的是正确性和简单性,而不是性能,这总是一个好主意,直到你描述了一个真实的设计模型。
很可能是在一个简化的测试中,非侵入性的速度是侵入性的两倍,然而在实际工作的实际程序中,这种速度差异在噪音中消失了,变得如此微不足道,以至于你甚至无法测量它。这是一种非常普遍的现象;您想象的对性能有重要意义的事情通常并不重要。
如果您发现了性能瓶颈,这是可能的(可能吗?)维护引用计数本身的工作(在这两种方法中)对性能的影响与非侵入性方法中的额外间接影响一样大。对于原始指针,语句:
p1 = p2;在优化器发挥了作用之后,可能只需要在两个CPU寄存器之间移动一个值。但是,如果它们是引用来计算智能指针,即使具有侵入性,这就像:
if (p1 != p2)
{
if ((p1 != 0) && (--(p1->count) == 0))
delete p1;
p1 = p2;
if (p1 != 0)
p1->count++;
}这种情况发生在传递给每个函数的每个智能指针参数中。因此,有许多额外的访问可能遥远的区域的记忆,以提高和降低计数每次。为了确保线程安全,增量和递减检查操作必须是互锁/原子操作,这可能对多核产生严重的负面影响。
我认为C++的“亮点”是这样一种情况,即您不需要管理这种非常动态的数据结构。相反,您有一个简单的对象所有权分层模式,因此每个对象都有一个明显的单一所有者,而且数据的生存期往往遵循函数调用的生存期(通常不是这样)。然后,您可以让标准容器和函数调用堆栈为您管理一切。这一点在即将推出的带有rvalue引用、unique_ptr等的语言版本中得到了强调,这一切都是为了以一种简单的方式围绕对象的单一所有权进行转移。如果您真的需要动态的多所有者生命周期管理,那么真正的GC将更快、更容易正确使用,但是对于GC来说,C++并不是一个非常愉快的家。
另一个小问题:不幸的是,“在非侵入式智能指针中,只有一个指针指向每个Foo”是不正确的。在Foo内部有一个this指针,它是一个Foo *,所以裸露的指针仍然可以泄漏出去,通常是很难找到的。
https://stackoverflow.com/questions/2486493
复制相似问题