Unique_ptr <Derived> neden unique_ptr <Base> öğesine dolaylı olarak yayınlanıyor?


21

Ben beklenen unique_ptr<Derived>yerde kullanan aşağıdaki kodu yazdımunique_ptr<Base>

class Base {
    int i;
 public:
    Base( int i ) : i(i) {}
    int getI() const { return i; }
};

class Derived : public Base {
    float f;
 public:
    Derived( int i, float f ) : Base(i), f(f) {}
    float getF() const { return f; }
};

void printBase( unique_ptr<Base> base )
{
    cout << "f: " << base->getI() << endl;
}

unique_ptr<Base> makeBase()
{
    return make_unique<Derived>( 2, 3.0f );
}

unique_ptr<Derived> makeDerived()
{
    return make_unique<Derived>( 2, 3.0f );
}

int main( int argc, char * argv [] )
{
    unique_ptr<Base> base1 = makeBase();
    unique_ptr<Base> base2 = makeDerived();
    printBase( make_unique<Derived>( 2, 3.0f ) );

    return 0;
}

ve ben bu kod derlemek değil beklediğim, çünkü benim anlayışım unique_ptr<Base>ve unique_ptr<Derived>ilgisiz türleri ve unique_ptr<Derived>aslında unique_ptr<Base>ödev işe yaramaz böylece türetilmiş değildir.

Ama biraz sihir sayesinde işe yarıyor ve nedenini ya da bunu yapmak güvenli olsa bile anlamıyorum. Birisi açıklayabilir mi lütfen?


3
akıllı işaretçiler, işaretçilerin onu sınırlamak için yapamayacağı şeyleri zenginleştirmektir. Bu mümkün unique_ptrolmasaydı miras varlığında işe yaramaz olurdu
idclev 463035818

3
"Ama sihir sayesinde işe yarıyor" . Neredeyse, Basesanal yıkıcıya sahip olmadığı için UB'ye sahipsiniz .
Jarod42

Yanıtlar:


25

Aradığınız sihir biraz burada dönüştürme yapıcı # 6 :

template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;

Son kullanma tarihi geçmiş bir std::unique_ptr<T>zımni olarakstd::unique_ptr<U> eğer (netlik için silicilere sayarlar):

unique_ptr<U, E>::pointer dolaylı olarak dönüştürülebilir pointer

Yani, türetilmiş baz bazında dönüşümler dahil, örtük ham işaretçi dönüşümlerini taklit eder ve beklediğiniz şeyi güvenli bir şekilde yapar (ömür boyu - temel türün polimorfik olarak silinebilmesini sağlamanız gerekir).


2
AFAIK'ın Basesilinmesi yıkıcı olarak adlandırılmayacak Derived, bu yüzden gerçekten güvenli olup olmadığından emin değilim. (Ham işaretçiden daha az güvenli değil, kuşkusuz.)
cpplearner

14

Çünkü std::unique_ptrbir dönüştürme yapıcısı

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

ve

Bu yapıcı yalnızca aşağıdakilerin tümü doğru olduğunda aşırı yük çözünürlüğüne katılır:

a) unique_ptr<U, E>::pointer örtük olarak dönüştürülebilirpointer

...

A dolaylı olarak Derived*dönüştürülebilir Base*, daha sonra bu yapıcı için dönüştürme yapıcısı uygulanabilir. Sonra a , ham işaretçinin yaptığı gibi dolaylı std::unique_ptr<Base>olarak dönüştürülebilir std::unique_ptr<Derived>. (Bunun özelliği nedeniyle std::unique_ptr<Derived>inşaat için bir rvalue olması gerektiğini unutmayın .)std::unique_ptr<Base>std::unique_ptr


7

Sen olabilir örtük bir inşa std::unique_ptr<T>, bir gelen örneği rvalue ait std::unique_ptr<S>her Sdönüştürülebilir olduğunu T. Bunun nedeni buradaki # 6 yapıcısıdır . Bu durumda sahiplik devredilir.

Örneğin, yalnızca tür değerlerine sahipsiniz std::uinque_ptr<Derived>(çünkü dönüş değeri std::make_uniquebir değerdir ) ve bunu a olarak kullandığınızda, std::unique_ptr<Base>yukarıda belirtilen yapıcı çağrılır. Dolayısıyla std::unique_ptr<Derived>söz konusu nesneler sadece kısa bir süre için yaşarlar, yani yaratılırlar, daha sonra sahiplik daha sonra std::unique_ptr<Base>kullanılan nesneye aktarılır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.