cod*_*nk1 2 c++ gcc unique-ptr c++11
我经常读到unique_ptr在大多数情况下比shared_ptr更受欢迎,因为unique_ptr是不可复制的并且具有移动语义; shared_ptr会因复制和引用计数而增加开销;
但是当我在某些情况下测试unique_ptr时,它看起来比它的对手明显更慢(在访问中)
例如,在gcc 4.5下:
编辑:打印方法实际上不打印任何内容
#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;
}
Run Code Online (Sandbox Code Playgroud)
我平均得到(g ++ -O0):
差异来自哪里?这可以解释吗?
Soh*_*neh 19
更新于2014年1月1日
我知道这个问题很老了,但结果仍然适用于G ++ 4.7.0和libstdc ++ 4.7.所以,我试图找出原因.
什么你标杆这里是解引用性能使用-O0和,看着实行unique_ptr和shared_ptr,你的结果实际上是正确的.
unique_ptr将指针和删除器存储在a中::std::tuple,同时shared_ptr直接存储裸指针句柄.因此,当您取消引用指针(使用*, - >或get)时,您需要额外调用::std::get<0>()in unique_ptr.相反,shared_ptr直接返回指针.在gcc-4.7上,即使在优化和内联时,:: std :: get <0>()比直接指针慢一点..优化和内联时,gcc-4.8.1完全省略了:: std :: get <0>()的开销.在我的机器上,当编译时-O3,编译器生成完全相同的汇编代码,这意味着它们在字面上是相同的.
总而言之,利用当前的实现,shared_ptr是在创建,移动,复制和引用计数速度较慢,但同样快速*上废弃*.
注意:问题中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(); }
Run Code Online (Sandbox Code Playgroud)
注意:这不是一个基本问题,可以通过在当前libstdc ++实现中放弃使用:: std :: tuple来轻松修复.
Pup*_*ppy 12
您在定时块中所做的只是访问它们.这根本不会涉及任何额外的开销.增加的时间可能来自控制台输出滚动.你永远不可能在定时基准测试中做I/O.
如果你想测试引用计数的开销,那么实际上做一些引用计数.shared_ptr如果你永远不变异,shared_ptr那么建造,破坏,分配和其他变异操作的时间增加会如何影响你的时间?
编辑:如果没有I/O那么编译器优化在哪里?他们应该完成整个事情.甚至意识形态也让这个人大吃一惊.