Как передать std:: уникальный ptr вокруг?
у меня есть моя первая попытка использовать C++11 unique_ptr
; я заменяю полиморфный необработанный указатель внутри моего проекта, который принадлежит одному классу, но передается довольно часто.
раньше у меня были такие функции, как:
bool func(BaseClass* ptr, int other_arg) {
bool val;
// plain ordinary function that does something...
return val;
}
но вскоре я понял, что не смогу переключиться на:
bool func(std::unique_ptr<BaseClass> ptr, int other_arg);
потому что вызывающий должен был бы обрабатывать владение указателем на функцию, чего я не хочу. Итак, какое лучшее решение для моего проблема?
Я думал о передаче указателя в качестве ссылки, например:
bool func(const std::unique_ptr<BaseClass>& ptr, int other_arg);
но я чувствую себя очень неудобно при этом, во-первых, потому что кажется не инстинктивным передать что-то уже набранное как _ptr
в качестве ссылки, что бы ссылка ссылки. Во-вторых, потому что сигнатура функции становится еще больше. В-третьих, потому что в сгенерированном коде было бы необходимо два последовательных косвенных указателя для достижения моей переменной.
4 ответа:
если вы хотите, чтобы функция использовала указатель, передайте ссылку на него. Нет причин привязывать функцию к работе только с каким-то умным указателем:
bool func(BaseClass& base, int other_arg);
и на сайте вызова используйте
operator*
:func(*some_unique_ptr, 42);
если
base
аргумент может быть null, сохранить подпись как есть, и использоватьget()
функции:bool func(BaseClass* base, int other_arg); func(some_unique_ptr.get(), 42);
преимущества использования
std::unique_ptr<T>
(кроме того, что не нужно помнить, чтобы позвонитьdelete
илиdelete[]
явно), что он гарантирует, что указатель либоnullptr
или он указывает на допустимый экземпляр (базового) объекта. Я вернусь к этому после того, как отвечу на ваш вопрос, но первое сообщение DO используйте интеллектуальные указатели для управления временем жизни динамически выделяемых объектов.сейчас, ваш
Я согласен с Мартиньо, но я думаю, что важно указать на семантику владения ссылкой на передачу. Я думаю, что правильное решение-использовать простую ссылку здесь:
bool func(BaseClass& base, int other_arg);
общепринятое значение pass-by-reference в C++ похоже на то, как если бы вызывающая функция сообщала функции: "здесь вы можете заимствовать этот объект, использовать его и изменять его (если не const), но только на время существования тела функции."Это ни в коем случае не конфликт с правилами владения
unique_ptr
поскольку объект просто заимствован на короткий период времени, фактическая передача прав собственности не происходит (если вы одолжите свой автомобиль кому-то, вы подпишете ему титул?).Итак, даже если это может показаться плохим (дизайн-мудрый, методы кодирования и т. д.) чтобы вытащить ссылку (или даже необработанный указатель) из
unique_ptr
, это на самом деле не потому, что он идеально соответствует правилам владения, установленнымunique_ptr
. И тогда, конечно, есть и другие приятные преимущества, такие как чистый синтаксис, отсутствие ограничений только на объекты, принадлежащие aunique_ptr
и так.
лично я избегаю вытаскивать ссылку из Указателя / смарт-указателя. Потому что что происходит, если указатель
nullptr
? Если вы измените подпись на это:bool func(BaseClass& base, int other_arg);
возможно, вам придется защитить свой код от разыменования нулевого указателя:
if (the_unique_ptr) func(*the_unique_ptr, 10);
если класс является единственным владельцем указателя, второй вариант Мартиньо кажется более разумным:
func(the_unique_ptr.get(), 10);
кроме того, вы можете использовать
std::shared_ptr
. Однако, если есть одна единственная сущность ответственный заdelete
наstd::shared_ptr
накладные расходы не окупятся.