Доброе утро!
Я уже затрагивал тему умных указателей, когда говорил про boost::offset_ptr
. В сегодняшней краткой заметке я хочу написать, почему как стандартный, так и бустовый smart_ptr
'ы стоит передавать по ссылке в ситуациях, когда это возможно.
Рассмотрим следующий код:
#include <chrono>
#include <iostream>
#include <memory>
#include <boost/smart_ptr/shared_ptr.hpp>
using namespace std::chrono;
struct sometype {
int x;
};
void stdspbyval(std::shared_ptr<sometype> p) {
(void)p;
}
void stdspbyref(const std::shared_ptr<sometype> &p) {
(void)p;
}
void boostspbyval(boost::shared_ptr<sometype> p) {
(void)p;
}
void boostspbyref(const boost::shared_ptr<sometype> &p) {
(void)p;
}
int main(int c, char **v) {
high_resolution_clock::time_point t1, t2;
std::shared_ptr<sometype> p = std::make_shared<sometype>();
t1 = high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
stdspbyval(p);
}
t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(t2 - t1).count();
std::cerr << "stdspbyval:\t" << duration << std::endl;
t1 = high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
stdspbyref(p);
}
t2 = high_resolution_clock::now();
duration = duration_cast<microseconds>(t2 - t1).count();
std::cerr << "stdspbyref:\t" << duration << std::endl;
boost::shared_ptr<sometype> pp{new sometype()};
t1 = high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
boostspbyval(pp);
}
t2 = high_resolution_clock::now();
duration = duration_cast<microseconds>(t2 - t1).count();
std::cerr << "boostspbyval:\t" << duration << std::endl;
t1 = high_resolution_clock::now();
for (int i = 0; i < 10000000; ++i) {
boostspbyref(pp);
}
t2 = high_resolution_clock::now();
duration = duration_cast<microseconds>(t2 - t1).count();
std::cerr << "boostspbyref:\t" << duration << std::endl;
(void)c;(void)v;
return 0;
}
Вызываются функции, которые ничего не делают. Функции принимают соответствующие указатели, по значению и по ссылке. Пример вывода:
$ ./pointers
stdspbyval: 643491
stdspbyref: 27704
boostspbyval: 394144
boostspbyref: 28561
Видим явное отличие в порядках времени выполнения между аналогичными указателями при передаче по ссылке и значению. Данное различие возникает по причине того, что счётчик ссылок в данных указателях — атомарная переменная. Это ведёт к тому, что при большом числе копирований может проседать производительность.
Вывод: если есть возможность, стоит отдать предпочтение передаче умного указателя по ссылке, а не по значению.