unique_ptr для производного класса в качестве аргумента функции, которая переводит unique_ptr в базовый класс
Я пытаюсь использовать unique_ptr
для производного класса в функции, которая переводит unique_ptr
в базовый класс. Что-то вроде:
class Base {};
class Derived : public Base {};
void f(unique_ptr<Base> const &base) {}
…
unique_ptr<Derived> derived = unique_ptr<Derived>(new Derived);
f(derived);
Если я правильно понимаю этот ответ, этот код должен работать, но он вызывает следующие ошибки компиляции:
ошибка C2664: "f": невозможно преобразовать параметр 1 из "std :: unique_ptr <_Ty>" в "const std :: unique_ptr <_Ty> &"
IntelliSense: не существует подходящего пользовательского преобразования из "std :: unique_ptr <Derived, std :: default_delete <Derived >>" в "const std :: unique_ptr <Base, std :: default_delete <Base >>"
Если я изменю f
на брать unique_ptr<Derived> const &derived
, он будет работать нормально, но это не то, что я хочу.
Я делаю что-то неправильно? Что я могу сделать, чтобы обойти это?
Я использую Visual Studio 2012.
Ответы
Ответ 1
У вас есть три варианта:
-
Отказ от собственности. Это оставит вашу локальную переменную без доступа к динамическому объекту после вызова функции; объект был передан вызываемому лицу:
f(std::move(derived));
-
Измените подпись f
:
void f(std::unique_ptr<Derived> const &);
-
Измените тип переменной:
std::unique_ptr<base> derived = std::unique_ptr<Derived>(new Derived);
Или, конечно, просто:
std::unique_ptr<base> derived(new Derived);
Или даже:
std::unique_ptr<base> derived = std::make_unique<Derived>();
-
Обновление: Или, как рекомендовано в комментариях, вообще не передавать права собственности:
void f(Base & b);
f(*derived);
Ответ 2
Возможное решение состоит в том, чтобы изменить тип аргумента как Base const*
и передать derived.get()
. Передача права собственности с помощью unique_ptr const<Base>&
(и unique_ptr
не изменяется), поэтому переход на Base const*
не меняет значения.
Herb Sutter обсуждает длинные аргументы интеллектуального указателя в Параметры интеллектуального указателя. Выдержка из связанной статьи относится к этой точной ситуации:
Передача const unique_ptr<widget>&
странная, потому что она может принимать только null
или widget
, чье время жизни управляется в вызывающем коде через unique_ptr
, и вызываемый обычно не должен заботиться о жизни вызывающих абонентов выбор управления. Передача widget*
охватывает строгий суперсет этих случаев и может принимать "null
или widget
" независимо от политики времени жизни, которую использует вызывающий объект.
Ответ 3
У меня был вариант № 1 принятого ответа, и у меня все еще была та же ошибка компиляции. Больше часа я бился головой о стену и наконец понял, что
class Derived : Base {};
вместо
class Derived : public Base {};