shared_from_this()如何在从继承自enabled_shared_from_this的基类继承的派生类中工作

时间:2016-09-11 03:32:55

标签: c++ inheritance shared-ptr

我想知道我的理解是否是关于shared_ptr和shared_from_this()如何工作以及内存分配如何工作的最新信息。

以下是我的课程:

   class Component : public enable_shared_from_this <Component>
{

public:
    Component() :enable_shared_from_this(){}

};

class DerivedComponent : public Component
{
public:

    DerivedComponent()
    {}

    void tryDerivedShared()
    {
        auto sptr1 = shared_from_this();
        if (this == sptr1.get())
            std::cout << "Both have same starting address";

    }

private:
    std::vector<int> myVector;
};

int main()
{

    auto sptr = make_shared<DerivedComponent>();
    sptr->tryDerivedShared();

}

当我从基类派生时,我理解的是内存首先分配给基础,然后分配给派生。所以,当我auto sptr1 = shared_from_this();发生了什么时,它会将shared_ptr返回给基类Component的对象。由于base是Derived类的内存的一部分,this == sptr1.get()的值是true,因为它们都返回它们指向的obj的起始内存。 基本上分配的内存类似于| Base | Derived |而shared_from_this()返回一个shared_ptr,只指向Base的对象,即| Base |大块的记忆。我的理解是否正确?

2 个答案:

答案 0 :(得分:0)

将这些类视为结构可能会更容易。只有您的基类为空,所以这可能不是最佳示例。

struct Component
{
};

派生时,实际上是将字段添加到结构中,但是您可能需要这样看待它:

struct DerivedComponent
{
    struct Component    component_;
    std::vector<int>    myVector;
};

因此,您是正确的,在分配DerivedComponent时,Component(或&obj.component_)的地址都相同,这就是为什么您可以{{1} }两者之间。

当您从许多类派生时,尤其是如果使用static_cast<>()关键字时,情况会变得更加复杂。另一方面,拥有虚函数并不太复杂,它会在开始时添加一个虚表指针,但是就您所担心的隐藏指针而言。

virtual不会改变这个概念。它只是向enable_shared_from_this()结构添加了一个弱指针。因此Component类看起来像这样:

Component

答案 1 :(得分:0)

  

我了解的是,首先为基础分配了内存,然后为派生分配了内存。

不。整个对象的内存在一次分配中获得。但是可以在构造数据成员期间进行其他分配。如果使用make_shared,则在该分配中甚至分配了支持shared_ptr所需的额外内存。

  

所以当我执行自动sptr1 = shared_from_this();发生的事情是将shared_ptr返回到基类Component的对象。

shared_from_this()返回类型为std::shared_ptr<Component>的对象,是的。

  

并且由于基数是Derived类的内存的一部分,因此== sptr1.get()的值为true,因为它们两个都返回它们指向的obj的起始内存。

不完全是。完全可以进行比较,因为Derived*可以隐式转换为Component*。并且由于sptr1实际上持有指向同一对象的指针,因此它们的比较结果相同。

  

基本上,分配的内存类似于| Base | Derived |。而shared_from_this()返回一个shared_ptr,它仅指向Base对象,即| Base |。大块的内存。

没有诸如“与指针绑定的内存块”之类的东西。指针只是内存中的地址。它所指向的内容的解释取决于指针的类型。您的内存布局几乎是正确的,但是在Base和Derived之间没有任何类型的定界符(在这种情况下)。在基类的数据成员之后,派生的数据成员立即占用内存。请注意,我们在这里谈论单一继承。您的sptr1可以用作指向Component*的指针,因为它的类型为shared_ptr<Component>。由于您已经采用DerivedComponent的方法,因此可以安全地使用std::static_pointer_cast<DerivedComponent>(sptr1)来获取shared_ptr<Derived>

由于shared_ptr存储使用它创建的实际类的删除器,所以即使保存的最后一个引用为shared_ptr<Component>,它也会调用正确的析构函数,即使它不是虚拟的。