Подтвердить что ты не робот

Передача unique_ptr в функции

Я пытаюсь "модернизировать" существующий код.

  • У меня есть класс, который в настоящее время имеет переменную-член "Device * device_".
  • Он использует новое для создания экземпляра в некотором коде инициализации и имеет "delete device_" в деструктории.
  • Функции-члены этого класса вызывают множество других функций, которые принимают Device * в качестве параметра.

Это хорошо работает, но чтобы "модернизировать" мой код, я думал, что должен изменить переменную, которая будет определена как "std::unique_ptr<Device> device_", и удалить явный вызов для удаления, что делает код более безопасным и вообще лучше.

Мой вопрос -

  • Как мне передать переменную device_ всем функциям, которые нуждаются в ней в качестве параметра?

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

Или я могу изменить каждую функцию, чтобы вместо того, чтобы принимать параметр типа "Устройство *", теперь он принимает параметр типа "std:: unique_ptr &". Который (мне) несколько запутывает прототипы функций и затрудняет их чтение.

Что лучше для этого? Я пропустил другие варианты?

4b9b3361

Ответ 1

В современном стиле С++ существуют две концепции ключей:

  • собственности
  • Недействительность

Собственность касается владельца какого-либо объекта/ресурса (в данном случае экземпляра Device). Различные std::unique_ptr, boost::scoped_ptr или std::shared_ptr относятся к собственности.

Nullity намного проще: он просто выражает, может ли данный объект быть нулевым, и не заботится ни о чем другом, и, конечно, не о собственности!


Вы были права переместить реализацию своего класса в сторону unique_ptr (в общем), хотя вам может понадобиться умный указатель с глубокой семантикой копирования, если ваша цель - реализовать PIMPL.

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


С другой стороны, большинству пользователей ресурсов не было все равно, как бы это ни было.

Пока функция не сохраняет ссылку на объект (сохраняет его на карте или что-то еще), тогда все, что имеет значение, - это то, что время жизни объекта превышает продолжительность вызова функции.

Таким образом, выбор способа передачи параметра зависит от его возможного Nullity:

  • Никогда не null? Передайте ссылку
  • Возможно, null? Передайте указатель, простой пустой указатель или указательный класс (например, с ловушкой на нулевом уровне)

Ответ 2

Это действительно зависит. Если функция должна принадлежать unique_ptr, то она должна иметь значение unique_ptr<Device> bv , а вызывающий должен std::move указатель. Если право собственности не является проблемой, я бы сохранил подпись необработанного указателя и передал указатель unique_ptr с помощью get(). Это не уродливое , если рассматриваемая функция не приобретает права собственности.

Ответ 3

Я бы использовал std::unique_ptr const&. Использование ссылки non const даст вызываемой функции возможность reset вашего указателя.
Я думаю, что это хороший способ выразить, что ваша вызываемая функция может использовать указатель, но ничего больше.
Поэтому для меня это упростит чтение интерфейса. Я знаю, что мне не нужно возиться с указателем, переданным мне.

Ответ 4

Лучшая практика, вероятно, не использовать std::unique_ptr в этом случае, хотя это зависит. (Обычно у вас не должно быть более одного сырья указатель на динамически выделенный объект в классе. Хотя это также зависит.) Единственное, что вы не хотите делать в этом случае: проходя вокруг std::unique_ptr (и, как вы заметили, std::unique_ptr<> const& является немного громоздким и запутывающим). Если это является единственным динамически выделенным указателем в объекте, я бы просто придерживался с необработанным указателем и delete в деструкторе. Если есть несколько таких указателей, я бы подумал о том, чтобы отнести каждого из них к отдельный базовый класс (где они все еще могут быть необработанными указателями).

Ответ 5

Это может быть невыполнимо для вас, но замена любого появления Device* на const unique_ptr<Device>& - хорошее начало.

Очевидно, вы не можете скопировать unique_ptr, и вы не хотите его перемещать. Замена ссылкой на unique_ptr позволяет телу тел существующих функций продолжать работать.

Теперь у вас есть ловушка, вы должны пройти мимо const &, чтобы препятствовать выполнению вызовов unique_ptr.reset() или unique_ptr().release(). Обратите внимание, что это все еще передает изменяемый указатель на устройство. С помощью этого решения у вас нет простого способа передать указатель или ссылку на const Device.