C++ 智能指针性能

Posted

技术标签:

【中文标题】C++ 智能指针性能【英文标题】:C++ Smart Pointer performance 【发布时间】:2008-11-21 11:24:55 【问题描述】:

与裸指针相比,使用智能指针,尤其是 boost::shared_ptr 在时间和内存方面的成本要高多少?对游戏/嵌入式系统的性能密集型部分使用裸指针是否更好?您会建议对性能密集型组件使用裸指针还是智能指针?

【问题讨论】:

【参考方案1】:

取消引用智能指针通常是微不足道的,当然对于发布模式的提升。所有 boost 检查都在编译时进行。 (智能指针理论上可以跨线程执行智能操作)。这仍然留下了许多其他操作。 Nicola 提到了建造、复制和破坏。不过,这不是完整的集合。其他重要的操作是交换、赋值和重置为 NULL。基本上,任何需要智能的操作。

请注意,其中一些操作被一些智能指针排除在外。例如。 boost::scoped_ptr 甚至不能被复制,更不用说被分配了。由于这留下了更少的操作,因此可以针对这些更少的方法优化实现。

事实上,随着 TR1 的出现,编译器很可能使用智能指针比原始指针做得更好。例如。编译器可能会证明智能不可复制指针在某些情况下没有别名,仅仅是因为它是不可复制的。想一想:当创建两个指向同一个对象的指针时,就会发生别名。如果第一个指针不能被复制,那么第二个指针怎么会指向同一个对象呢? (也有一些方法可以解决这个问题 - operator* 必须返回一个左值)

【讨论】:

不幸的是,您对优化智能指针的想法行不通,至少在 C++ 中是这样。在将指针放入智能指针之前,您可能已将指针存储在其他位置。此外,通过执行 &*smart_ptr; 可以轻松(但不建议)将原始 C 指针从智能指针中取出 我同意克里斯·杰斐逊的观点。在将其放入智能指针之前,没有人阻止您将其存储在其他地方 我在这里写了一个关于别名的小答案:***.com/questions/270408/… 您确实可以从原始指针初始化 scoped_ptr,在这种情况下编译器无法优化。我的观点是,这是个例外。编译器在优化时需要排除这些不常见的情况,就像它需要排除 &*MySmartPtr 情况一样。【参考方案2】:

Boost 提供不同的智能指针。一般来说,内存占用(根据智能指针的种类而异)和性能应该不是问题。如需性能比较,您可以查看此http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/smarttests.htm。

正如您所见,性能比较只考虑了构造、复制和销毁,这意味着取消引用智能指针的成本应该与原始指针的成本相同。

以下 sn-p 表明使用 shared_ptr<> 代替原始指针不会降低性能:

#include <iostream>
#include <tr1/memory>

int main()

#ifdef USE_SHARED_PTR
    std::tr1::shared_ptr<volatile int> i(new int(1));
#else
    volatile int * i = new int(1);
#endif

    long long int h = 0;

    for(long long int j=0;j < 10000000000LL; j++)
    
        h += *i;
    

    std::cout << h << std::endl;
    return 0;

【讨论】:

【参考方案3】:

处理性能问题的唯一方法是分析您的代码。无论如何,性能问题的最大部分是想象的;只有分析才能向您指出瓶颈所在。

如果事实证明使用智能指针会产生原始指针不会产生的瓶颈,请使用原始指针!在那之前,我不会太担心它;大多数对智能指针的操作都相当快。您可能过于频繁地比较字符串(或类似的东西),以至于它们并不重要。

【讨论】:

【参考方案4】:

引用计数智能指针(最常见的类型)只会在您复制、创建和删除它们时花费更多。如果您要进行大量复制,这种额外的成本可能会很大,因为它们中的大多数都是线程安全的。

如果您只想要一个“自动删除”指针,那么可以使用备受诟病的 auto_ptr,或者来自 C++0x 的新的、闪亮的(但还没有太多支持的)unique_ptr。

【讨论】:

【参考方案5】:

当我上次使用 VC6 进行测试时,编译器无法像使用原始指针那样优化使用智能指针的代码。从那以后情况可能会发生变化。

【讨论】:

上次使用 VC6 测试旧版本的 boost(我认为是 1.34)时,编译器优化了weak_ptr 的引用计数的原子增量。这使事情运行得更快,尽管在线程库中造成了很多崩溃。 我意识到 VC6 仍然被不能轻易切换的大型项目大量使用,但在这里公平地说,在 VS.NET 产品生命周期中的第二个版本 VC2003 之前,它还不是一个成熟的编译器循环。【参考方案6】:

在“手动”管理的std::vector&lt;T*&gt;(即原始指针)和std::vector&lt;boost::shared_ptr&lt;T&gt; &gt; 之间有一个经常被忽视的中间点,其形式为boost::ptr_container 类。

它们结合了原始指针容器的性能和智能指针容器的便利性(即它们提供了人们希望std::auto_ptr 的 STL 容器提供的功能,if that worked)。

【讨论】:

以上是关于C++ 智能指针性能的主要内容,如果未能解决你的问题,请参考以下文章

C++智能指针

C++智能指针详解:智能指针的引入

C++ 和智能指针——智能指针在这种情况下有啥帮助?

C++单线程智能指针实现

C++编程经验:智能指针 -- 裸指针管得了的我要管,裸指针管不了的我更要管!

C++编程经验:智能指针 -- 裸指针管得了的我要管,裸指针管不了的我更要管!