我已经读到创建或复制std::shared_ptr会涉及一些开销(引用计数器的原子增量等)。
但是如何从中创建std::weak_ptr呢?
Obj * obj = new Obj();
// fast
Obj * o = obj;
// slow
std::shared_ptr<Obj> a(o);
// slow
std::shared_ptr<Obj> b(a);
// slow ?
std::weak_ptr<Obj> c(b);
我希望能够获得更快的性能,但是我知道共享指针仍然必须增加弱引用计数器。
那么,这仍然像将shared_ptr复制到另一个一样慢吗?
最佳答案
除了Alec's非常有趣的描述他以前的项目中使用的shared/weak_ptr系统之外,我还想提供更多有关典型std::shared_ptr/weak_ptr
实现可能发生的情况的详细信息:
// slow
std::shared_ptr<Obj> a(o);
上述结构的主要费用是分配一个内存块来保存两个引用计数。此处不需要执行原子操作(除了在
operator new
下实现可能会或可能不会执行的操作之外)。// slow
std::shared_ptr<Obj> b(a);
复制结构中的主要费用通常是单个原子增量。
// slow ?
std::weak_ptr<Obj> c(b);
此
weak_ptr
构造函数中的主要开销通常是单个原子增量。我希望该构造函数的性能几乎与shared_ptr
复制构造函数的性能相同。要注意的另外两个重要的构造函数是:
std::shared_ptr<Obj> d(std::move(a)); // shared_ptr(shared_ptr&&);
std::weak_ptr<Obj> e(std::move( c )); // weak_ptr(weak_ptr&&);
(以及匹配的移动分配运算符)
move构造函数根本不需要任何原子操作。他们只是将引用计数从rhs复制到lhs,并使rhs == nullptr。
仅当在分配之前执行lhs!= nullptr时,移动分配运算符才需要原子减量。在移动分配之前的大部分时间(例如,在
vector<shared_ptr<T>>
中)lhs == nullptr,因此根本没有原子操作。后者(
weak_ptr
move成员)实际上不是C++ 11,但由LWG 2315处理。但是,我希望大多数实现已经实现了它(我知道它已经在libc++中实现了)。当在容器中搜寻智能指针时,将使用这些移动成员,例如在
vector<shared_ptr<T>>::insert/erase
下,与使用智能指针拷贝成员相比,可以产生可衡量的积极影响。我指出这一点是为了让您知道,如果您有机会移动而不是复制
shared_ptr/weak_ptr
,那么键入一些额外的字符是很麻烦的。
关于C++ weak_ptr创建性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20290524/