派生 class 的智能指针如何隐式转换为基数 class?
How are smart pointers of a derived class implicitly convertible to the base class?
来自 cppreference,
If T
is a derived class of some base B
, then std::unique_ptr<T>
is
implicitly convertible to std::unique_ptr<B>
这显然必须是多态性才能像处理原始指针一样工作。我的问题是,如果智能指针通常不能转换为我们可以看到的指针 ,那么智能指针使用什么机制来允许运行时多态性?我的想法是,在构造函数或 std::make_unique<>()
/std::make_shared<>()
中,对象中的内部指针用于此转换。但是,如果在其他任何地方都不允许这些隐式转换,为什么我们在构造智能指针时不必调用 get() 呢?
作为一个非常简单的例子,我提出了以下测试:
#include <iostream>
#include <memory>
class Base
{
public:
virtual ~Base() = default;
virtual void foo() const { std::cout << "Base foo() called." << std::endl; }
};
class Derived : public Base
{
public:
virtual void foo() const override { std::cout << "Derived foo() called." << std::endl; }
};
void bar(Base* pBase)
{
std::cout << "bar() called." << std::endl;
pBase->foo();
}
int main()
{
std::unique_ptr<Base> pObject { std::make_unique<Derived>() }; // Implicit conversion here, why no call to get()?
// bar(pObject); // Can't be converted, so we have to call get()
bar(pObject.get());
}
My question is, if a smart pointer is not generally convertible to a pointer as we can see here, then what is the mechanism used by the smart pointer to allow for runtime polymorphism?
智能指针明确设计用于使这种转换成为可能。正如您在 std::unique_ptr
构造函数中看到的那样 documentation:
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; (6)
此重载是为此目的创建的。
This constructor only participates in overload resolution if all of
the following is true:
a) unique_ptr<U, E>::pointer is implicitly
convertible to pointer
b) U is not an array type
c) Either Deleter is
a reference type and E is the same type as D, or Deleter is not a
reference type and E is implicitly convertible to D
重点是我的。因此,指向派生 class 的指针是隐式的
可转换为基础此构造函数重载使此类转换成为可能。
从 .get()
返回的指针不会将所有权转移给调用者(即 .release()
)。
如果你使用 .get()
的指针构造另一个 smart-pointer 你将得到一个 double-free.
所以这是一个错误:
std::unique_ptr<Base> pObject { std::make_unique<Derived>().get() };
这有效
std::unique_ptr<Base> pObject { std::make_unique<Derived>().release() };
而对于 shared_ptr
,从 .get()
和 .release()
构建是错误的,因为您可能有其他实例具有相同的 shared-state 而您没有转移。所以你最终可能会得到两个 smart-pointers 指向同一个指针但有不同的 shared-state.
来自 cppreference,
If
T
is a derived class of some baseB
, thenstd::unique_ptr<T>
is implicitly convertible tostd::unique_ptr<B>
这显然必须是多态性才能像处理原始指针一样工作。我的问题是,如果智能指针通常不能转换为我们可以看到的指针 std::make_unique<>()
/std::make_shared<>()
中,对象中的内部指针用于此转换。但是,如果在其他任何地方都不允许这些隐式转换,为什么我们在构造智能指针时不必调用 get() 呢?
作为一个非常简单的例子,我提出了以下测试:
#include <iostream>
#include <memory>
class Base
{
public:
virtual ~Base() = default;
virtual void foo() const { std::cout << "Base foo() called." << std::endl; }
};
class Derived : public Base
{
public:
virtual void foo() const override { std::cout << "Derived foo() called." << std::endl; }
};
void bar(Base* pBase)
{
std::cout << "bar() called." << std::endl;
pBase->foo();
}
int main()
{
std::unique_ptr<Base> pObject { std::make_unique<Derived>() }; // Implicit conversion here, why no call to get()?
// bar(pObject); // Can't be converted, so we have to call get()
bar(pObject.get());
}
My question is, if a smart pointer is not generally convertible to a pointer as we can see here, then what is the mechanism used by the smart pointer to allow for runtime polymorphism?
智能指针明确设计用于使这种转换成为可能。正如您在 std::unique_ptr
构造函数中看到的那样 documentation:
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; (6)
此重载是为此目的创建的。
This constructor only participates in overload resolution if all of the following is true:
a) unique_ptr<U, E>::pointer is implicitly convertible to pointer
b) U is not an array type
c) Either Deleter is a reference type and E is the same type as D, or Deleter is not a reference type and E is implicitly convertible to D
重点是我的。因此,指向派生 class 的指针是隐式的 可转换为基础此构造函数重载使此类转换成为可能。
从 .get()
返回的指针不会将所有权转移给调用者(即 .release()
)。
如果你使用 .get()
的指针构造另一个 smart-pointer 你将得到一个 double-free.
所以这是一个错误:
std::unique_ptr<Base> pObject { std::make_unique<Derived>().get() };
这有效
std::unique_ptr<Base> pObject { std::make_unique<Derived>().release() };
而对于 shared_ptr
,从 .get()
和 .release()
构建是错误的,因为您可能有其他实例具有相同的 shared-state 而您没有转移。所以你最终可能会得到两个 smart-pointers 指向同一个指针但有不同的 shared-state.