我经常读到,在大多数情况下,unique_ptr 会比 share_ptr 更受青睐,因为 unique_ptr 是不可复制的,并且具有移动语义;由于复制和引用计数,shared_ptr 会增加开销;
但是当我在某些情况下测试 unique_ptr 时,它似乎比其对应项明显慢(访问)
例如,在gcc 4.5 :
edit: print 方法实际上并不打印任何内容
#include <iostream>
#include <string>
#include <memory>
#include <chrono>
#include <vector>
class Print{
public:
void print(){}
};
void test()
{
typedef vector<shared_ptr<Print>> sh_vec;
typedef vector<unique_ptr<Print>> u_vec;
sh_vec shvec;
u_vec uvec;
//can't use initializer_list with unique_ptr
for (int var = 0; var < 100; ++var) {
shared_ptr<Print> p(new Print());
shvec.push_back(p);
unique_ptr<Print> p1(new Print());
uvec.push_back(move(p1));
}
//-------------test shared_ptr-------------------------
auto time_sh_1 = std::chrono::system_clock::now();
for (auto var = 0; var < 1000; ++var)
{
for(auto it = shvec.begin(), end = shvec.end(); it!= end; ++it)
{
(*it)->print();
}
}
auto time_sh_2 = std::chrono::system_clock::now();
cout <<"test shared_ptr : "<< (time_sh_2 - time_sh_1).count() << " microseconds." << endl;
//-------------test unique_ptr-------------------------
auto time_u_1 = std::chrono::system_clock::now();
for (auto var = 0; var < 1000; ++var)
{
for(auto it = uvec.begin(), end = uvec.end(); it!= end; ++it)
{
(*it)->print();
}
}
auto time_u_2 = std::chrono::system_clock::now();
cout <<"test unique_ptr : "<< (time_u_2 - time_u_1).count() << " microseconds." << endl;
}
平均我得到 (g++ -O0) :
- 共享指针:1480 微秒
- unique_ptr:3350微秒
差异从何而来?可以解释吗?
更新于 2014 年 1 月 1 日
我知道这个问题已经很老了,但结果在 G++ 4.7.0 和 libstdc++ 4.7 上仍然有效。于是,我试图找出原因。
您在这里进行的基准测试是解引用性能 using -O0并且,考虑到实施情况unique_ptr
and shared_ptr
,你的结果实际上是正确的。
unique_ptr
将指针和删除器存储在::std::tuple
, while shared_ptr
直接存储裸指针句柄。因此,当您取消引用指针(使用 *、-> 或 get)时,您需要额外调用::std::get<0>()
in unique_ptr
。相比之下,shared_ptr
直接返回指针。 在 gcc-4.7 上,即使经过优化和内联,::std::get() 也比直接指针慢一点。。经过优化和内联后,gcc-4.8.1 完全省略了 ::std::get() 的开销。在我的机器上,当编译时-O3
,编译器生成完全相同的汇编代码,这意味着它们是字面上地相同。
总而言之,使用当前的实现,shared_ptr
创建、移动、复制和引用计数速度较慢, but 同样快 *关于解除引用*.
NOTE: print()
问题中为空,编译器在优化时会忽略循环。因此,我稍微修改了代码以正确观察优化结果:
#include <iostream>
#include <string>
#include <memory>
#include <chrono>
#include <vector>
using namespace std;
class Print {
public:
void print() { i++; }
int i{ 0 };
};
void test() {
typedef vector<shared_ptr<Print>> sh_vec;
typedef vector<unique_ptr<Print>> u_vec;
sh_vec shvec;
u_vec uvec;
// can't use initializer_list with unique_ptr
for (int var = 0; var < 100; ++var) {
shvec.push_back(make_shared<Print>());
uvec.emplace_back(new Print());
}
//-------------test shared_ptr-------------------------
auto time_sh_1 = std::chrono::system_clock::now();
for (auto var = 0; var < 1000; ++var) {
for (auto it = shvec.begin(), end = shvec.end(); it != end; ++it) {
(*it)->print();
}
}
auto time_sh_2 = std::chrono::system_clock::now();
cout << "test shared_ptr : " << (time_sh_2 - time_sh_1).count()
<< " microseconds." << endl;
//-------------test unique_ptr-------------------------
auto time_u_1 = std::chrono::system_clock::now();
for (auto var = 0; var < 1000; ++var) {
for (auto it = uvec.begin(), end = uvec.end(); it != end; ++it) {
(*it)->print();
}
}
auto time_u_2 = std::chrono::system_clock::now();
cout << "test unique_ptr : " << (time_u_2 - time_u_1).count()
<< " microseconds." << endl;
}
int main() { test(); }
NOTE:这不是一个根本问题,可以通过在当前 libstdc++ 实现中放弃使用 ::std::tuple 来轻松解决。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)