【发布时间】:2020-08-07 13:40:33
【问题描述】:
来自cppreference,
如果
T是某个基类B的派生类,那么std::unique_ptr<T>是 隐式转换为std::unique_ptr<B>
显然,多态性必须像处理原始指针一样工作。我的问题是,如果智能指针通常不能转换为我们可以看到的指针here,那么智能指针使用什么机制来实现运行时多态性?我的想法是在构造函数或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());
}
【问题讨论】:
-
隐式转换 ...正确。 为什么不调用 get()? ...因为这行不通,你最终会得到两个智能指针来管理同一个对象的生命周期。
-
@Eljay 如果这两个是
shared_ptr<>而不是unique_ptr<>的情况也会如此吗? -
更抽象地思考。您首先声明某个类可以隐式转换为另一个类。为什么你期望这个隐式转换首先需要隐式转换到
T*?为什么要向最终用户公开隐式转换的内部机制? -
是的,如果你从智能指针中取出原始指针,而不让智能指针放弃原始指针的所有权,然后将它交给另一个智能指针来管理,两个智能指针都会不知不觉地管理了对象的生命周期。在一个智能指针销毁对象后,另一个智能指针对现在删除的对象的任何使用(包括删除它)都将导致未定义的行为。这是一件坏事™。
-
@JaMiT 我想我被绊倒了,因为如果没有到 T* 的转换,更多的类不能被没有指针的派生类型实例化吗?也许这实际上是允许的,我只是让它变得比它需要的更复杂
标签: c++ smart-pointers