考虑这个程序:
#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
数的机制。只能查询强计数(通过shared_ptr::use_count
)。请注意,在多线程环境中,这允许是近似计数(即使用memory_order_relaxed
负载)。
您确定这是性能瓶颈吗?
考虑allocate_shared
。它使用分配器创建shared_ptr
。可以将释放shared_ptr的控制块缓存在分配器中,并立即在下一次allocate_shared
调用中重用它,从而保存删除和新建。
我怀疑这会有很大的不同。在多线程应用程序中,此分配器可以快速且正确。