2013-07-04 7 views
29

Я пытаюсь использовать 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); 

Если я понимаю this answer правильно, этот код должен работать, но это вызывает следующие ошибки компиляции:

ошибка C2664: «F»: не удается преобразовать параметр 1 из «станд: : unique_ptr < _Ty>»на 'сопзЬ станд :: unique_ptr < _Ty> &'

IntelliSense: нет подходящего определяемые пользователем преобразование из«STD :: unique_ptr < Derived, станд :: default_delete < Der ived >>»к "сопзЬ станд :: unique_ptr < базы, станд :: default_delete < Base >>" существует

Если изменить f принять unique_ptr<Derived> const &derived, он отлично работает, но это не то, что я хочу.

Я что-то не так? Что я могу сделать, чтобы обойти это?

Я использую Visual Studio 2012.

ответ

39

У вас есть три варианта:

  1. отказаться от собственности. Это оставит вашу локальную переменную без доступа к динамическому объекту после вызова функции; объект был передан вызываемым:

    f(std::move(derived)); 
    
  2. Изменить подпись f:

    void f(std::unique_ptr<Derived> const &); 
    
  3. Изменить тип переменной:

    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>(); 
    
  4. Update: Или, как это рекомендовано в комментариях, не передавать право собственности на все:

    void f(Base & b); 
    
    f(*derived); 
    
+1

В этом случае я рассматриваю возможность использования 4. Используйте 'shared_ptr'. – svick

+2

Как просто использовать ссылку вместо unique_ptr для вызова функции? – ltjax

+5

@svick, зачем передавать умный указатель на функцию, если она не принимает права на указатель? Для этого не нужны умные указатели. –

8

possibile решение изменить тип аргумента должен быть Base const*, а вместо этого передать derived.get(). Передача права собственности с unique_ptr const<Base>& (и не изменяется), поэтому изменение на Base const* не меняет значения.


Herb Sutter обсуждает прохождение интеллектуальных аргументов указатель на длину в Smart Pointer Parameters.Выписка из связанного статьи относится к этой конкретной ситуации:

пропускании const unique_ptr<widget>& это странно, потому что она может принимать только как null или widget, время жизни которых происходит управляться в коде вызова через unique_ptr и вызываемая как правило, не должен заботиться о выборе управления временем жизни звонящего. Передача widget* охватывает строгий набор этих случаев и может принимать «null или widget» независимо от политики времени жизни, которую использует вызывающий абонент.

+0

Не означает, что 'Base const *' означает, что функция может хранить указатель где-нибудь? Я, хотя умные указатели, пытается избежать этого. – svick

+0

@svick, функция может хранить 'base.get()' так же легко ('get()' является функцией 'const'). – hmjd

+0

@svick Нет. Умные указатели должны избегать утечек памяти, выясняя, кто является владельцем объекта. Если вы передаете необработанный указатель в качестве аргумента функции, вы просто предоставляете доступ для чтения/изменения. Умные указатели должны избегать использования сырых 'новых' и' delete', а не указателей. – etam1024

Смежные вопросы