繁体   English   中英

如何使用静态强制转换来管理共享对象的生命周期?

[英]How to manage shared object lifetimes with static casts?

我是C ++样式转换的新手,并且需要帮助来理解下面的代码如何工作(这是我编写的一些了解情况的伪代码)。

#include <iostream>
#include <memory>

class A { 
public:
    A() : a(1) {
        std::cout << "Creating A\n";
    }   
    ~A() {
        std::cout << "Destroying A\n";
    }   
    int a;
};

class B : public A { 
public:
    B() : b(2) {
        std::cout << "Creating B\n";
    }   
    ~B() {
        std::cout << "Destroying B\n";
    }   
    int b;
};

int main() {
    std::shared_ptr<B> objectB(new B());
    {   
    std::shared_ptr<A> (static_cast<A*>(objectB.get()));
    std::cout << "End of inner scope\n";
    }   
    std::cout << "End of outer scope\n";
}

它打印

Creating A
Creating B
Destroying A
End of inner scope
End of outer scope
Destroying B
Destroying A

我的理解:

Creating A         -> B's ctor calls base class ctor
Creating B         -> B's ctor
Destroying A       -> ???
End of inner scope
End of outer scope
Destroying B       -> B's dtor
Destroying A       -> B's dtor calls base dtor

为什么我会得到第一个Destroying A以及这里到底发生了什么?! 如何将A销毁两次?

如果您确保输出已刷新(例如,使用std::endl ),则会得到

创造A.

创造B.

摧毁A.

内部范围结束

外部范围结束

摧毁B.

摧毁A.

两次删除A的原因是您要从此处的原始指针构造一个shared_ptr

std::shared_ptr<A> (static_cast<A*>(objectB.get()));

这个shared_ptr完全独立于第一个,并且有自己的引用计数。 因此,当范围结束时,它会尝试删除它所持有的A指针。 如果您这样做,则:

std::shared_ptr<A>{objectB};

那么您就不会遇到问题。 请注意,此处不需要static_cast

请注意, A应该具有virtual析构函数。 shared_ptr具有聪明的销毁机制,这意味着在此示例中这并不重要,但是通常,如果要多态删除对象,则基类必须具有虚拟析构函数。

如果从juanchopanza的回答中不清楚这条线

std::shared_ptr<A> (static_cast<A*>(objectB.get()));

是不正确的,导致未定义的行为。

您在此处构造的共享指针仅使用您提供的指针。 不知道该指针指向的对象已被另一个智能指针拥有。 此外,它不知道指针指向一个子对象,并且该指针将需要被static_castB*才能delete d,因为static_cast会将信息隐藏在其中。

要投射智能指针,您需要一个能够理解并与智能指针集成在一起的演员表。 为此,C ++具有std::static_pointer_caststd::dynamic_pointer_cast

int main() {
  std::shared_ptr<B> objectB(new B());
  {   
    std::shared_ptr<A> x = std::static_pointer_cast<A>(objectB);
    std::cout << "End of inner scope\n";
  }   
  std::cout << "End of outer scope\n";
}

使用此代码,程序的输出将显示正确的行为:

make A
make B
End of inner scope
End of outer scope
~B
~A

当然,在这种特殊情况下,您不需要显式转换,因为std::shared_ptr可以找出合法的转换并隐式执行。 你需要std::static_pointer_cast进行向下转换:

int main() {
  std::shared_ptr<A> objectA(new B());
  {   
    std::shared_ptr<B> x = std::static_pointer_cast<B>(objectA);
    std::cout << "End of inner scope\n";
  }   
  std::cout << "End of outer scope\n";
}

谢谢,最后一件事,如果我不需要objectB,可以安全地执行std::shared_ptr<A> objectA(new B());

是的,这确实是安全的。 shared_ptr<A>构造函数接收B*并且知道足以存储这样的事实:当发生删除时,它将需要将它保持的A*转换为B* 这可确保正确删除对象。

但是,如果您确实希望类型A和类型B具有多态性,则应该通过添加虚拟析构函数使它们成为多态类型,然后不必担心std::shared_ptr多么聪明。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM