ОБНОВЛЕН 01 января 2014 года
Я знаю, что этот вопрос довольно старый, но результаты все еще действительны для G ++ 4.7.0 и libstdc ++ 4.7.Итак, я попытался выяснить причину.
Здесь вы оцениваете производительность разыменования с использованием -O0 и, глядя на реализацию unique_ptr
и shared_ptr
, ваши результаты на самом деле верны.
unique_ptr
сохраняет указатель и средство удаления в ::std::tuple
, тогда как shared_ptr
хранит непосредственно дескриптор обнаженного указателя.Таким образом, когда вы разыменовываете указатель (используя *, -> или get), у вас есть дополнительный вызов ::std::get<0>()
в 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(); }
ПРИМЕЧАНИЕ : Это не принципиальная проблема, которую можно легко устранить, отказавшись от использования:: std :: tuple в текущей реализации libstdc ++.