优化替换共享指针内容时对分配器的调用

Optimize calls to allocator when replacing the content of a shared pointer

本文关键字:分配器 调用 替换 共享 指针 优化      更新时间:2023-10-16

考虑这个程序:

#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的引用计数;如果计数变为零,则没有其他弱引用,并且Uptr内容派生最多的类型,它会破坏拥有的对象,并使用args在同一内存区域中的参数构造一个新对象,从而避免调用内存分配器。否则它的行为就像ptr = std::make_shared<U>(args).

是否可以使用当前标准库执行此优化?

没有计算共享对象weak_ptr数的机制。只能查询强计数(通过shared_ptr::use_count)。请注意,在多线程环境中,这允许是近似计数(即使用memory_order_relaxed负载)。

您确定这是性能瓶颈吗?

考虑allocate_shared。它使用分配器创建shared_ptr。可以将释放shared_ptr的控制块缓存在分配器中,并立即在下一次allocate_shared调用中重用它,从而保存删除和新建。

我怀疑这会有很大的不同。在多线程应用程序中,此分配器可以快速且正确。