与C ++中的普通指针相比,智能指针的开销是多less?

与C ++ 11中的普通指针相比,智能指针的开销是多less? 换句话说,如果我使用智能指针,我的代码会变慢,如果是这样,慢多less?

具体来说,我问的是C ++ 11 std::shared_ptrstd::unique_ptr

显然,按下堆栈的东西会更大(至less我是这么认为的),因为一个智能指针还需要存储其内部状态(引用计数等),问题实际上是,这是多less影响我的performance,如果有的话?

例如,我从一个函数而不是一个普通的指针返回一个智能指针:

 std::shared_ptr<const Value> getValue(); // versus const Value *getValue(); 

或者,例如,当我的一个函数接受一个智能指针作为参数,而不是一个正常的指针:

 void setValue(std::shared_ptr<const Value> val); // versus void setValue(const Value *val); 

std::unique_ptr只有在提供了一些非平凡的删除器时才会有内存开销。

std::shared_ptr总是有引用计数器的内存开销,尽pipe它非常小。

std::unique_ptr只有在构造函数(如果它必须复制提供的deleter和/或null初始化指针)和析构函数(销毁拥有的对象)期间才有时间开销。

std::shared_ptr在构造函数(创build引用计数器),析构函数(减less引用计数器,可能销毁对象)和赋值运算符(增加引用计数器)中有时间开销。 由于std::shared_ptr线程安全保证,这些增量/减量是primefaces的,因此增加了一些开销。

请注意,它们中没有一个在解引用(在获取对拥有对象的引用)中有时间开销,而这个操作似乎是指针最常见的。

总之,有一些开销,但是不应该让代码变慢,除非你不断创build和销毁智能指针。

与所有的代码性能一样,唯一真正可靠的获取硬信息的方法是测量和/或检查机器代码。

这就是说,简单的推理说

  • debugging版本中可能会有一些开销,因为例如operator->必须作为一个函数调用来执行,这样就可以进入它(这反过来又是由于普遍缺乏将类和函数标记为非debugging的支持)。

  • 对于shared_ptr ,在初始创build中可能会有一些开销,因为这涉及dynamic分配控制块,dynamic分配比C ++中的其他基本操作(在实际可能的情况下使用make_shared ,以最小化开销)要慢得多。

  • 同样对于shared_ptr ,在维护一个引用计数方面有一些最小的开销,例如当通过值传递一个shared_ptr时,但是对于unique_ptr没有这样的开销。

记住上面的第一点,当你测量的时候,对于debugging和发布版本都要这样做。

国际C ++标准化委员会已经发布了一个关于性能的技术报告 ,但是这是在2006年,在unique_ptrshared_ptr被添加到标准库之前。 不过,聪明的指针在那个时候已经是老帽子了,所以报告也考虑到了这一点。 引用相关部分:

“如果通过一个简单的智能指针访问一个值比通过一个普通的指针访问一个值要慢得多,那么编译器就无法有效地处理这个抽象了。 过去,大多数编译器都有明显的抽象惩罚,现在还有一些编译器。 然而,据报至less有两个编制者的抽象惩罚低于1%,另一个惩罚是3%,所以消除这种开销就属于现有技术水平“

据了解,截至2014年初,现在最stream行的编译器已经实现了“最佳状态”。

换句话说,如果我使用智能指针,我的代码会变慢,如果是这样,慢多less?

比较慢? 很可能不会,除非你用shared_ptrs创build了一个巨大的索引,并且你没有足够的内存来让你的电脑开始起皱,就像一位老太太被一股来自远方的难以承受的力量猛地摔倒在地。

什么会让你的代码更慢,search缓慢,不必要的循环处理,庞大的数据副本,以及大量的写操作到磁盘(如数百)。

智能指针的优点都与pipe理有关。 但是,必要的开销? 这取决于你的实现。 假设您正在迭代3个阶段的数组,每个阶段都有一个由1024个元素组成的数组。 为这个过程创build一个smart_ptr可能是矫枉过正的,因为一旦迭代完成,你就会知道你必须清除它。 所以你可以从不使用smart_ptr获得额外的内存…

但是你真的想这么做吗?

单一的内存泄漏可能会让你的产品在时间上失败(假设你的程序每小时泄漏4兆字节,这将需要几个月的时间才能打破计算机,但是会破坏,你知道它是因为漏洞在那里) 。

就好比说“你的软件保证3个月,然后打电话给我服务”。

所以最终确实是一个…你能处理这个风险吗? 使用一个原始指针来处理你的索引数百个不同的对象值得失去对内存的控制。

如果答案是肯定的,则使用原始指针。

如果你甚至不想考虑它, smart_ptr是一个好的,可行的,真棒解决scheme。