派生 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.