Рассмотрим следующий вектор:
std::vector<std::shared_ptr<X>> myVector;
и следующие две функции, которые добавляют данный элемент к вектору:
void foo1(std::shared_ptr<X> x)
{
myVector.push_back(x);
}
void foo2(const std::shared_ptr<X>& x)
{
myVector.push_back(x);
}
Я понимаю, что обе функции толкают shared_ptr
в X
в вектор и, таким образом, увеличить счетчик ссылок X
, Первая функция приводит к дополнительному увеличению и уменьшению счетчика ссылок, но это не нужно.
Правильно ли мое понимание? Поэтому предпочтительнее второй вариант?
В foo1
Вы передаете параметр (т.е. общий указатель) по значению. Таким образом, конструктор копирования std::shared_ptr<X>
будет вызываться (т.е. счетчик ссылок будет увеличиваться, а затем уменьшаться при вызове деструктора локальной копии в }
из foo1
).
В foo2
Вы передаете параметр (т.е. общий указатель) const
ссылка. Таким образом, вы передаете const
квалифицированный псевдоним исходного объекта (то есть счетчик ссылок не будет увеличен).
Вы также можете увидеть это в следующем примере:
struct X {};
void foo1(std::shared_ptr<X> x) {
std::cout << "count in foo1(): " << x.use_count() << std::endl;
}
void foo2(const std::shared_ptr<X>& x) {
std::cout << "count in foo2(): " << x.use_count() << std::endl;
}
int main() {
std::shared_ptr<X> x(new X);
std::cout << "count in main(): " << x.use_count() << std::endl;
foo1(x);
foo2(x);
}
count in main(): 1
count in foo1(): 2
count in foo2(): 1
Как вы можете видеть в foo1
количество различных экземпляров shared_ptr равно 2. Это оригинал shared_ptr
определяется в main
и копия в foo1
, Принимая во внимание, что в foo2
счетчик ссылок остается 1.
Следовательно, ваши рассуждения верны.
Вы должны переписать свои функции как:
void foo1(std::shared_ptr<X> x)
{
myVector.emplace_back(std::move(x));
}
void foo2(const std::shared_ptr<X>& x)
{
myVector.emplace_back(x);
}
тогда обе версии должны быть более эффективными, что будет зависеть от ситуации и конкретного компилятора, скорее всего, разница будет очень мала, если таковая имеется.
Обычно лучше передавать общий указатель по ссылке, так как атомарные приращения, как правило, ухудшают производительность. В вашем случае это не будет заметно, так как вы потом копируете его.