为什么unique_ptr <Derived>隐式转换为unique_ptr <Base>?

时间:2019-10-01 08:44:17

标签: c++ templates inheritance unique-ptr

我编写了以下使用unique_ptr<Derived>的代码,其中预期unique_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;
}

,我希望此代码不会编译,因为根据我的理解,unique_ptr<Base>unique_ptr<Derived>是不相关的类型,而unique_ptr<Derived>实际上不是从unique_ptr<Base>派生的,因此分配不起作用。

但是由于某种神奇的效果,它起作用了,我不知道为什么,即使这样做是安全的。 有人可以解释吗?

3 个答案:

答案 0 :(得分:25)

您正在寻找的神奇之处是转换构造函数#6 here

library(PKI) #or library(encryptr)
tt  <- is.na(mat)
tt <- cbind(tt, matrix(TRUE, nrow(tt), ncol=(8 - ncol(tt) %% 8)))
tt <- raw2hex(packBits(t(tt)))
tt <- matrix(tt, ncol = nrow(mat))
tt <- apply(tt, 2, paste, collapse="")
match(tt, unique(tt))
[1] 1 2 3 2 3

通过启用template<class U, class E> unique_ptr(unique_ptr<U, E> &&u) noexcept; if (为清楚起见,在删除器上进行光泽显示),可以隐式构造std::unique_ptr<T>

  

std::unique_ptr<U>可隐式转换为unique_ptr<U, E>::pointer

这就是说,它可以模仿隐式原始指针转换,包括派生到基本的转换,并且可以安全地执行您期望的操作(就生命周期而言,您仍然需要确保基本类型可以多态删除)

答案 1 :(得分:13)

因为std::unique_ptr的转换构造函数为

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

  

该构造函数仅在满足以下所有条件时才参与重载解析   以下是正确的:

     

a)unique_ptr<U, E>::pointer可隐式转换为pointer

     

...

Derived*可以隐式转换为Base*,然后可以在这种情况下应用转换构造函数。然后可以像原始指针一样,从std::unique_ptr<Base>隐式转换std::unique_ptr<Derived>。 (请注意,由于std::unique_ptr<Derived>的特性,std::unique_ptr<Base>必须是构造std::unique_ptr的右值。)

答案 2 :(得分:7)

只要std::unique_ptr<T>可转换为{{1},就可以根据std::unique_ptr<S> rvalue 隐式构造一个S实例。 }。这是由于构造器#6 here。在这种情况下,所有权是转移的。

在您的示例中,您只有类型T的右值(因为std::uinque_ptr<Derived>的返回值是右值),当您将其用作std::make_unique时,构造函数提到上面的被调用。因此,所讨论的std::unique_ptr<Base>对象仅存在很短的时间,即它们被创建,然后所有权被传递给std::unique_ptr<Derived>对象,该对象将进一步使用。