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

C++ 在替换共享指针的内容时优化对分配器的调用,c++,smart-pointers,C++,Smart Pointers,考虑一下这个计划: #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() {

考虑一下这个计划:

#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;
}
#包括
结构T{
T(){}
};
void do__某物(std::shared_ptr ptr){
//用ptr做点什么;可能离开,也可能不离开
//其他变量中的ptr的其他副本
//节目
}
int main(){
std::shared_ptr ptr=std::make_shared();
做点什么(ptr);
//ptr可能是也可能不是唯一的所有者
ptr=std::使_共享();
返回0;
}
当第二次执行
make_shared
时,
ptr
可能有或可能有其他共享所有者,这取决于运行时在
do_something
中发生的情况。如果没有其他对象,
ptr
在差不多同时分配和构造了同一时间的新对象时,销毁并解除分配其以前拥有的对象。有没有办法避免分配和取消分配,并使用相同的区域来构造新对象?(这里的目标是优化对分配器的两个调用)

当然,我接受新的
T
对象将在旧对象被破坏后被构造,而在上面的代码中,相反的情况会发生。因此,我想要类似于
ptr.replace(args)
的东西,它会减少
ptr
的引用计数;如果计数变为零,则没有其他弱引用,并且
U
ptr
内容的最派生类型,它将销毁所拥有的对象,并在同一内存区域中使用参数
args
构造一个新对象,从而避免调用内存分配器。否则它的行为类似于
ptr=std::make_shared(args)


对于当前的标准库,是否仍有执行此优化的方法?

没有统计共享对象的
弱\u ptr
数量的机制。您只能查询强计数(通过
shared\u ptr::use\u count
)。请注意,在多线程环境中,这是允许的近似计数(即使用
内存\u顺序
加载)

您确定这是性能瓶颈吗

考虑一下。它使用分配器创建一个
共享的\u ptr
。可以在分配器中缓存释放的共享\u ptr的控制块,并在下一次
allocate\u shared
调用中立即重用它,保存删除和新建


我怀疑这会有多大不同。在多线程应用程序中,此分配器在快速和正确执行方面可能非常重要。

通过分析代码,您是否发现这确实是一个大问题?如果不是,你不应该在意。澄清一下:你想要一个(免费)函数,它可以使用
std::shared_ptr
完成你需要的功能,还是你准备重新实现
std::shared_ptr
?在第一种情况下,您显然无法获得
ptr.replace(args)
(您不能只向其中添加一个方法),但“使用当前标准库”与第二种库不匹配。@TobiasBrösamle我知道,但我要求学习。@MaxLanghof如果您是对的,我有点太快了:我很想知道是否有一个解决方案可以直接应用于标准库,但不需要它是
std::shared\u ptr
的成员函数。一些列表
替换\u共享\u ptr(ptr,args)
也可以。如果我从头开始重新实现
std::shared_ptr
,我会知道该怎么做(或多或少如我所述),但我要问的是,标准库是否已经有空间进行这种优化。这不是我想要的,因为它无论如何都需要对共享资源(这种“缓存预分配器”)进行几次调用。我想利用您将在差不多相同的时间释放和分配两个大小相同的区域的机会。不过,谢谢你@乔凡尼马斯切拉尼我知道你的意思。这是最好的。无论如何,一个具有单个缓存元素的简单分配器(返回到另一个分配器)大部分都可以由编译器进行优化(至少对于微不足道的取消分配情况)。