Как передать 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 58

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. И тогда, конечно, есть и другие приятные преимущества, такие как чистый синтаксис, отсутствие ограничений только на объекты, принадлежащие a unique_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 накладные расходы не окупятся.