【问题标题】:How shared_from_this() works in the derived class which inherits from base class inheriting from enabled_shared_from_thisshared_from_this() 如何在从基类继承的派生类中工作,该基类继承自 enabled_shared_from_this
【发布时间】:2016-09-11 03:32:55
【问题描述】:

我想知道我对 shared_ptrshared_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 返回给基类组件的对象。而且由于基类是 Derived 类的内存的一部分,this == sptr1.get() 的值是true,因为它们都返回了它们指向的 obj 的起始内存。 基本上分配的内存就像 |Base|Derived| shared_from_this() 返回一个 shared_ptr 仅指向 Base 的对象,即 |Base|一大块内存。

我的理解正确吗?

【问题讨论】:

  • sptr1.get() 返回一个Component *this 是一个DerivedComponent *。比较运算符只能比较指向相同类型的指针,并且由于 DerivedComponent * 可以强制转换为 Component *,所以会发生这种情况,并且您最终会得到相同的指针值。相等比较真的和shared_from_this()无关。
  • 我明白你的意思。谢谢!
  • 如果你看thissptr1.get()的值是一样的,这意味着sptr是DerivedComponent创建的Component obj上的shared_ptr,它们共享相同的起始地址.我说的对吗?
  • 这是错误的:“当我从基类派生时,我的理解是先为基类分配内存,然后再为派生分配内存”。任何对象都有一个确切的大小:所有数据成员的组合大小(从基数到派生数)。

标签: c++ inheritance shared-ptr


【解决方案1】:

将这些类视为结构可能更容易。只有你的基类是空的,所以这可能不是最好的例子。

struct Component
{
};

派生时,实际上是向结构中添加字段,但您可能希望这样看待:

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

因此,您是对的,当您分配DerivedComponent 时,Component(或&amp;obj.component_)的地址都是相同的,这就是为什么您可以在两者之间使用static_cast&lt;&gt;()

当您从许多类派生时,尤其是使用virtual 关键字时,情况会变得更加复杂。另一方面,拥有虚函数并不太复杂,它在开头添加了一个虚表指针,但就您而言,指针是隐藏的。

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

struct Component
{
    struct enable_shared_from_this   shared_;
};

【讨论】:

    【解决方案2】:

    我的理解是,内存是先分配给基数的,然后再分配给派生的。

    没有。在一次分配中获取整个对象的内存。但是在数据成员的构建过程中可以进行额外的分配。在 make_shared 的情况下,甚至支持 shared_ptr 所需的额外内存也会在该一次分配中分配。

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

    shared_from_this() 返回一个std::shared_ptr&lt;Component&gt; 类型的对象,是的。

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

    不完全是。这种比较是完全可能的,因为Derived* 可以隐式转换为Component*。因为sptr1 实际上持有指向同一个对象的指针,所以它们比较相等。

    基本上分配的内存就像 |Base|Derived|并且 shared_from_this() 返回一个 shared_ptr 仅指向 Base 的对象,即 |Base|一大块内存。

    没有“与指针绑定的内存块”这样的东西。指针只是内存中的一个地址。它指向什么的解释取决于指针的类型。您的内存布局几乎是正确的,但是 Base 和 Derived 之间没有任何类型的分隔符(在这种情况下)。 Derived 的数据成员紧跟在 Base 类的数据成员之后占用内存。请注意,我们在这里讨论的是单继承。您的sptr1 可以用作指向Component* 的指针,只是因为它的类型为shared_ptr&lt;Component&gt;。由于您已经使用DerivedComponent 的方法,因此使用std::static_pointer_cast&lt;DerivedComponent&gt;(sptr1) 获取shared_ptr&lt;Derived&gt; 是安全的。

    由于shared_ptr 存储了创建它的实际类的删除器,即使最后持有的引用是shared_ptr&lt;Component&gt;,它也会调用正确的析构函数,即使它不是虚拟的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-10
      • 2019-05-22
      • 2010-10-05
      • 2014-12-23
      • 2021-08-24
      • 2012-02-12
      相关资源
      最近更新 更多