Передача std :: shared_ptr по значению или const ref и затем сохранение в контейнере?

Рассмотрим следующий вектор:

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, Первая функция приводит к дополнительному увеличению и уменьшению счетчика ссылок, но это не нужно.

Правильно ли мое понимание? Поэтому предпочтительнее второй вариант?

3

Решение

В 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.

Следовательно, ваши рассуждения верны.

2

Другие решения

Вы должны переписать свои функции как:

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);
}

тогда обе версии должны быть более эффективными, что будет зависеть от ситуации и конкретного компилятора, скорее всего, разница будет очень мала, если таковая имеется.

3

Обычно лучше передавать общий указатель по ссылке, так как атомарные приращения, как правило, ухудшают производительность. В вашем случае это не будет заметно, так как вы потом копируете его.

0
По вопросам рекламы [email protected]