Как передать shared_ptr в изменяемый объект в качестве параметра? - PullRequest
7 голосов
/ 05 декабря 2011

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

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

void foo (shared_ptr<bar> p)

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

void foo (const shared_ptr<bar> &p)

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

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

РЕДАКТИРОВАТЬ - Вероятно, стоит упомянуть - одна из причин для рассмотрения случая передачи по константной ссылке состоит в том, что существует уже существующее соглашение, которое в большинствеэкземпляры класса / структуры передаются по const-ссылке, а не по значению, а shared_ptr является классом.Конечно, это не тяжеловесный класс (стоимость копирования невелика), поэтому причины этого более старого соглашения могут не применяться.

Ответы [ 4 ]

13 голосов
/ 05 декабря 2011

Всегда передавать shared_ptr с по значению. Если вы передадите ссылку, вы можете столкнуться с проблемой, заключающейся в том, что вызов функции объекта, управляемого shared_ptr, может просто сбросить ее, и теперь у вас есть свисающий указатель. Если вы передадите по значению, вы убедитесь, что объект переживет текущий вызов функции.

См. здесь , чтобы получить гораздо больше информации.


Пример:

#include <memory>
#include <iostream>

std::shared_ptr<int> ptr(new int(42));

void foo(){
  ptr.reset();
}

void bar(std::shared_ptr<int> const& p){
  foo();
  std::cout << *p;
}

int main(){
  bar(ptr);
}

Это должно быть принято с щепоткой соли. Его можно адаптировать, чтобы доказать, что никакой тип никогда не должен передаваться по константной ссылке - см., Например, http://ideone.com/1IYyC,, на который Бенджамин Линдли указал в комментариях.

Однако на практике более сложные варианты такого рода проблем возникают случайно. Это, например, причина, по которой нас предупреждают, что итераторы (а также возвращаемые значения const-reference) становятся недействительными методами, которые изменяют контейнер, на который ссылаются. Этим правилам достаточно просто следовать, но иногда более косвенные и неожиданные примеры могут застать людей врасплох.

В таком случае лучше избегать дополнительного слоя ссылок, когда он не нужен.

0 голосов
/ 05 декабря 2011

Я проходил мимо и основывался на идее, что где-то в стеке вызовов кто-то должен хранить копию shared_ptr, и поэтому его жизнь гарантирована для всего моего исполнения.

В случае, если вы выполняете в другом потоке, вам нужна копия - и в этом случае любому, кто хранит , shared_ptr (а не только использует его во время их метода) должен хранитькопия, а не ссылка.

И теперь, когда я написал, я пойду и прочитаю, почему люди, кажется, поддерживают противоположный менталитет.

0 голосов
/ 05 декабря 2011

Если функция манипулирует объектом, она не должна быть релевантной, если объект содержится в интеллектуальном указателе.Следует принять T&.Свободные функции, манипулирующие значениями, считаются плохим стилем.Взятие объекта по ссылке на const и возврат нового значения может быть чище.

0 голосов
/ 05 декабря 2011

Пример того, что @Xeo сказал:

void foo(shared_ptr<bar> &p)
{
    p.reset(); // ref_count == 0; memory is freed.
}

shared_ptr<bar> p(new bar); // ref_count == 1
foo(p);

Этого не происходит для const shared_ptr<bar> &p.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...