C++智能指针性能

18

在时间和内存方面,使用智能指针,特别是boost::shared_ptr相比裸指针会增加多少开销?在游戏/嵌入式系统的性能密集部分中,使用裸指针是否更好?您是否建议在性能密集组件中使用裸指针还是智能指针?

6个回答

21

解引用智能指针通常很简单,特别是在boost的release模式下。所有boost检查都是在编译时进行的。(理论上智能指针可以在不同线程之间实现智能操作)。这仍然留下了许多其他操作。尼古拉提到了构造、复制和销毁。虽然这不是完整的集合,但还有其他重要的操作,如交换、赋值和重置为NULL。基本上,任何需要智能处理的操作。

请注意,一些智能指针排除了其中的某些操作。例如,boost::scoped_ptr 甚至不能被复制,更不能被分配。由于这减少了操作数,因此可以为这些较少的方法进行优化。

事实上,随着TR1的出现,编译器可能比裸指针更擅长处理智能指针。例如,编译器可以证明在某些情况下,一个智能的不可复制的指针并没有别名,只是因为它是不可复制的。想想看:当两个指针指向同一个对象时,才会发生别名。如果第一个指针无法被复制,第二个指针怎么会指向同一个对象呢?(也有办法绕过这个问题——operator*必须返回一个左值)


很遗憾,你对优化智能指针的想法在C++中不起作用。在将指针放入智能指针之前,你可能已经将其存储在其他地方。此外,通过执行&*smart_ptr,可以轻松(但不建议)从智能指针中获取原始的C指针。 - Chris Jefferson
我同意Chris Jefferson的观点。在将其放入智能指针之前,没有人会阻止您将其存储在其他地方。 - Johannes Schaub - litb
我在这里写了一个小答案关于别名问题:https://dev59.com/qHVC5IYBdhLWcg3whBaj - Johannes Schaub - litb
你确实可以从原始指针初始化scoped_ptr,这样编译器就无法进行优化。我的观点是这只是个例外。编译器需要在优化时排除这些不常见的情况,就像它需要排除&*MySmartPtr的情况一样。 - MSalters

7
Boost提供不同的智能指针。通常情况下,根据智能指针的种类,内存占用和性能都不应该成为问题。您可以查看此链接进行性能比较:http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/smarttests.htm
正如您所看到的,性能比较只考虑了构造、复制和销毁操作,这意味着解引用智能指针的成本应该与原始指针相同。
以下代码片段演示了使用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;
}

6

解决性能问题的唯一方法是对你的代码进行分析。大部分性能问题都只存在于想象中;只有通过分析才能找出瓶颈所在。

如果使用智能指针会导致瓶颈而裸指针不会,那么就使用裸指针!在此之前,不必过多担心;智能指针上的大多数操作都相当快速。你可能会过于频繁地比较字符串(或类似的操作),以至于它们并不重要。


2

引用计数智能指针(最常见的类型)只有在复制、创建和删除它们时才会增加成本。如果您需要频繁进行复制,这种额外成本可能相当大,因为大多数智能指针都是线程安全的。

如果您只需要一个“自动删除”的指针,则可以使用备受诟病的auto_ptr,或者来自C++0x的新型炫酷(但支持程度不高)unique_ptr。


2

在我上次使用VC6进行测试时,编译器不能像使用裸指针那样优化智能指针的代码。自那时以来可能已经有所改变。


2
当我最后一次使用VC6测试旧版本的boost(我想是1.34)时,编译器优化了weak_ptr的refcount的原子增量。这使得事情运行得更快,尽管在线程库中引起了相当多的崩溃。 - Michel
VC6目前仍被大型项目广泛使用,因为这些项目难以轻易转换。但是,公正地说,在VS.NET产品生命周期内,直到VC2003的第二个版本发布之前,它并不是一款成熟的编译器。 - ApplePieIsGood

2
有一种常被忽视的中间方式,介于“手动”管理的std::vector<T*>(即原始指针)和std::vector<boost::shared_ptr<T> >之间,即boost::ptr_container类。这些类结合了原始指针容器的性能和智能指针容器的便利性(即它们提供了人们希望STL容器的std::auto_ptr提供的功能,如果那样可行)。

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