什么时候适合将 unique_ptr 分配给共享_ptr?

问题描述 投票:0回答:1

这是对此处提出的问题的后续:C++11 unique_ptr 和 shared_ptr 能够转换为彼此的类型吗?更具体地说是投票最高的答案

引起我注意的片段是这样的:

这是 std::unique_ptr 如此适合作为工厂函数返回类型的关键部分。工厂函数无法知道调用者是否想要对它们返回的对象使用独占所有权语义,或者共享所有权(即 std::shared_ptr)是否更合适。通过返回 std::unique_ptr,工厂为调用者提供了最有效的智能指针,但它们并不妨碍调用者用更灵活的同级指针替换它。

然后我看到一个重复的问题是否允许将 unique_ptr 分配给共享_ptr?有评论:

为什么不应该呢?它甚至比分配常规指针更安全...[此处有更多文字]。

但是用户没有详细说明为什么它比分配常规指针更安全。我想知道在什么情况下最好将 unique_ptr 分配给共享_ptr?如果我理解正确,第一个引用的部分,像这样的情况是最好的:(假设我们有一个工作基类

Car
并且所有
CarType
都继承自
Car
。)

enum class CarType
{
    Sedan,
    SUV,
    Crossover,
    Truck,
    Bus
};

class MyRental
{
  public:
    MyRental();

    void assignRentalCar(CarType type);
    void doDriveAction();
    void doTurnAction();
    void doParkAction();

  private:
    std::shared_ptr<Car> currentCar;
    std::shared_ptr<Bus> bus; // a Oversized Vehicle Bus : (public OversizedCar : public Car)

};

从上面我们的私有成员中可以说,我们有一个特殊情况,其中成员变量

bus
继承自
OversizeCar
类,而该类又继承于
Car
类。

MyRental::MyRental() : currentCar(std::make_unique<Sedan>()),
                       bus(std::make_unique<Bus>())
{}
                         

void MyRental::assignRentalCar(CarType type)
{
  switch(type)
  {
    case CarType::SUV: currentCar = std::make_unique<SUV>(); break;
    case CarType::Crossover: currentCar = std::make_unique<Crossover>(); break;
    case CarType::Truck: currentCar = std::make_unique<Truck>(); break;
    case CarType::Bus: currentCar = bus; break; // allowed because currentCar is a shared_ptr
    case CarType::Sedan:
    case default: currentCar = std::make_unique<Sedan>(); break;
  }
}

void MyRental::doDriveAction()
{
  currentCar->handleDrive();
}

void MyRental::doTurnAction()
{
  currentCar->handleTurn();
}

void MyRental::doParkAction()
{
  currentCar->handlePark();
}

这是将

unique_ptr
分配给
shared_ptr
的适当情况吗?如果是这样,为什么它是合适的?如果分配
shared_ptr
不合适且更好,那么什么时候最好将
unique_ptr
分配给
shared_ptr

c++ polymorphism factory smart-pointers
1个回答
0
投票

我想知道在什么情况下最好将 unique_ptr 分配给共享_ptr?

你想太多了,但我认为这是一个有效的问题。分配合理的情况是当以下情况成立时。

  1. 您有一个类型为
    u
    的值
    U
    可以从中进行分配。
  2. 您有一个要分配给类型为
    s
    的对象
    S
  3. 赋值
    s = u
    在语法上是有效的并且对您的代码有用。
  4. 施工
    S s(u)
    不是一个合理的选择。 如果您可以合理地使用构造而不是赋值,那就这样做。

这些标准适用于许多类型,包括当

U
std::unique_ptr&&
S
std::shared_ptr
时。对于智能指针情况的一个警告是赋值必须来自右值。也就是说,如果函数没有返回
unique_ptr
,您可能必须移动它,如
s = std::move(u)
所示。请注意,此移动分配将导致
u
为空;您不会让
s
u
同时指向同一个对象。

基本上,在自然的情况下使用赋值,在不自然的情况下避免使用。


不过,你确实问的是“最好”而不是“好”。这带来了另一个考虑,也不是智能指针特有的:避免不必要的转换。将

unique_ptr<Truck>
分配给
shared_ptr<Car>
涉及的转换比将
shared_ptr<Truck>
转换为
shared_ptr<Car>
更复杂。在您的示例中,您可以通过将
std::make_unique
替换为
std::make_shared
来轻松简化。保持简单,不要强迫别人问“
unique_ptr
是否会转换为
shared_ptr

基本上,当可以选择时,请坚持使用

shared_ptr

© www.soinside.com 2019 - 2024. All rights reserved.