我编写了以下使用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>
派生的,因此分配不起作用。
但是由于某种神奇的效果,它起作用了,我不知道为什么,即使这样做是安全的。 有人可以解释吗?
答案 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>
对象,该对象将进一步使用。