为什么std::tr1::shared_ptr<>.reset()这么耗费资源?

4

我是一名帮助翻译文本的助手。

在对使用shared_ptr的代码进行性能分析时,我发现reset()函数的开销非常大。

例如:

struct Test {
    int i;
    Test() {
        this->i = 0;
    }
    Test(int i) {
        this->i = i;
    }
} ;
...
auto t = make_shared<Test>(1);
...
t.reset(somePointerToATestObject);

在 VC++ 2010 下追踪最后一行的 reset(),我发现它创建了一个新的引用计数对象。

有没有更便宜的方法,可以重复使用现有的引用计数,并且不会干扰堆内存?


3
他不知道。你知道 make_shared 是什么吗? - fredoverflow
@fred:我以为我做了。这不就是和Qt的QSharedPointer一样的东西吗? - ianmac45
别担心。shared_ptr的reset不是你的瓶颈,而且永远也不会是。 - John
“从软件开发的角度来看,绝对不是一个很强烈的词。如果你在内部循环中复制构造shared_ptr,那么它将成为你的瓶颈。如果使用正确,它不应该成为瓶颈,但这并不意味着它永远不会成为瓶颈。” - Billy ONeal
约翰,你并没有真正回答这个问题。如果你不喜欢这个问题,可以投反对票并发表评论说明原因。但我认为这是一个好问题。即使那种特定的方法永远不会成为瓶颈,了解它的本质仍然很有用,这样我们就可以从中学习,并将新知识应用于我们遇到的其他问题。 - Rob Kennedy
显示剩余3条评论
1个回答

4

一般情况下,您无法重用现有的引用计数,因为可能还有其他 shared_ptr weak_ptr 在使用它。

如果您可以使用 make_shared()创建 somePointerToATestObject ,那么实现可能会将单个堆分配用于引用计数和对象。 这将为您节省一个堆分配。


很遗憾,reset() 没有接受 shared_ptr<> 作为参数的版本。 - Benjamin Nitlehoo
4
@Paul:没错,你只需要像这样赋值:t = otherSharedPtr - James McNellis
@Charles:没错。就像我在评论中说的那样,应该简单地使用赋值。我在回答中想表达的是,当somePointerToATestObject被创建时,应立即将其分配给shared_ptr。然后你就不必担心使用reset()了。我不确定你对哪部分持有异议 :-/. - James McNellis
是你的第一句话让我感到困惑。如果将 somePointerToATestObject 传递给 reset,那么它除了是一个裸指针之外就什么也不是了,所以我不明白“现有引用计数”从哪里来。裸指针并不一定与现有引用计数相关联。如果裸指针实际上来自另一个 shared_ptr,那么这就是一个程序员的错误。reset 没有办法或者不应该使用其引用计数;这将违反接口。 - CB Bailey
@Charles:哦,我是指在重置之前shared_ptr所指向的对象的引用计数,这也是我认为OP在提到“重用现有引用计数”时所指的内容。对于一般情况,这是不可能做到的,因为shared_ptr没有独占所有者语义(如果它具有这种语义,那么它就不需要引用计数)。 - James McNellis
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接