考虑这个程序:
#include <memory>
struct T {
T() {}
};
void do_something(std::shared_ptr<T> ptr) {
// Do something with ptr; might or might not leave
// other copies of ptr in other variables of the
// program
}
int main() {
std::shared_ptr<T> ptr = std::make_shared();
do_something(ptr);
// ptr might or might not be the only owner
ptr = std::make_shared();
return 0;
}
当make_shared
第二次执行时,ptr
可能或可能有其他共享所有者,具体取决于do_something
在运行时发生的情况。如果没有其他的,ptr
会破坏和释放它以前拥有的对象,当或多或少同时分配和构造同一个新对象时。有没有办法避免分配和释放,并使用相同的区域来构建新对象? (这里的目标是优化对分配器的两次调用)
当然我接受新的T
对象将在旧的对象被破坏之后被构造,而在上面的代码中则相反。所以我想像ptr.replace<U>(args)
那样做以下事情:它减少了ptr
的引用计数;如果计数变为零,则没有其他弱引用,U
是ptr
内容的最派生类型,它会破坏拥有的对象,并在同一内存区域构造一个带有参数args
的新对象,从而避免调用内存分配器。否则它的行为就像ptr = std::make_shared<U>(args)
。
无论如何使用当前的标准库执行此优化?
没有机制可以将weak_ptr
s的数量计算到共享对象。您只能查询强计数(通过shared_ptr::use_count
)。请注意,在多线程环境中,允许这是一个近似计数(即使用memory_order_relaxed
加载)。
你确定这是性能瓶颈吗?
考虑一下allocate_shared
。它创建了一个带分配器的shared_ptr
。可以在分配器中缓存已释放的shared_ptr的控制块,并立即在下一个allocate_shared
调用中重用它,从而保存delete和new。
我怀疑它会有很大的不同。在多线程应用程序中,此分配器可以非常重要,以便快速和正确。