【问题标题】:How to keep one object alive as long as another object exists?只要另一个对象存在,如何使一个对象保持活动状态?
【发布时间】:2021-07-26 19:02:23
【问题描述】:

有没有办法防止一个特定对象在另一个对象仍然存在时被销毁, 明确地让第二个对象的类知道第一个对象?

这是一个例子:

class A { /* A creates B*/ };
class B {};

int main() {
    auto spA = std::make_shared<A>();
    auto spB = spA->getB();

    spA.reset();
    spB->DoSomething(); 
}

spA.reset() 之后,我希望至少有一个对spA 指向的对象的引用。或者,换句话说:我只想在调用spB-&gt;DoSomething() 之后销毁spA 指向的对象。

但是,一个重要的先决条件是不允许B“知道”A(例如,不允许持有指向它的指针/引用)。

据我了解,共享指针提供了一些有助于解决此问题的功能,但我不确定是哪一个。

编辑:

AB的简要结构如下:

class A 
{
public:
    A() 
    { 
        m_B = B::FactoryB(); 
    }
    std::shared_ptr<B> getB()
    {
        return m_B;
    }
private:
    std::shared_ptr<B> m_B; 
};

class B 
{
public:
    static std::shared_ptr FactoryB()
    {
        return std::make_shared<B>();
    }
};

EDIT2(我的解决方案):

因此,使用@MSalters 提供的建议,我能够找到适合我的解决方案。在这种情况下,它比预期的要简单得多,因此我只需要调整A::getB()

    std::shared_ptr<B> getB()
    {
        std::shared<B> spBAlias(this->shared_from_this(), m_B.get());
        return spBAlias;
    }

这里,A::getB() 创建并返回B 类型的共享指针spBAlias(使用别名构造函数),而不只是返回m_B,这会影响A 对象的引用计数(由this-&gt;shared_from_this())。因此,在main 中调用spA.reset() 可以将spA 的使用从2 减少到1,从而使spB-&gt;DoSomething() 的调用成为可能。要使用shared_from_this()A需要继承自std::enable_shared_from_this&lt;A&gt;

class A : public std::enable_shared_from_this<A> { /* ... */ }

【问题讨论】:

  • 我觉得你的问题有点混乱。如果您仍然希望对象还活着,为什么还要调用spA.reset()
  • 您似乎正试图将手动生命周期管理硬塞进shared_ptr。这几乎可以保证不会有好的结局。
  • @AndyG,例如,这只是对“不需要的”访问的模拟(例如,另一个函数/客户端试图删除另一个仍在使用的组件)。
  • 没有办法做到这一点并遵守这些严格的要求。 C++ 不能以这种方式工作。有可能做到这一点,但只需对这些要求稍作改动即可。
  • 对我来说,您似乎希望两者之间有明确的关系,但两者之间没有明确的关系,但也许我只是误解了您想要实现的目标

标签: c++ shared-ptr ownership-semantics


【解决方案1】:

您完全可以使用shared_ptr 来做到这一点,但您必须编写一些额外的代码。

只需让getB 返回一个带有自定义删除器的shared_ptr&lt;B&gt; ...删除器应该是一个 lambda,它按值捕获 shared_ptr&lt;A&gt;,并且仅在 spB 时显式释放 超出范围并尝试删除 B 对象。

A 必须从 std::enable_shared_from_this 派生,才能从 A::getB() 内部获取指向自身的可行共享指针。

如果B 对象实际上是A 的子对象,那么这就足够了。否则,你真的应该删除B


int main() {
    shared_ptr<A> spA = std::make_shared<A>();
    shared_ptr<B> spB = spA->getB();

    spA.reset();         // spB's deleter keeps the refcount nonzero
    spB->DoSomething();  // fine
}                        // spB's destructor finally deletes *spA

【讨论】:

  • 谢谢!我真的很喜欢你的想法,但我不太确定如何实现它。尤其是 lambda 捕获提供 this-&gt;shared_from_this() 对象的部分让我感到困惑,因为我在工厂函数中而不是在 A::getB() 中构造 B 对象。我用AB 的结构编辑了主要问题。您能否详细说明如何在我的情况下定义此自定义删除器功能?
  • 啊,我看到你现在已经描述了一点 B 的所有权模型,所以这应该是可能的。无论如何,要点是A 必须使用shared_from_this,这样A::getB() 才能获得指向this 的共享指针。然后它可以返回一个带有删除器的shared_ptr&lt;B&gt;,该删除器捕获该shared_ptr&lt;A&gt;
【解决方案2】:

shared_ptr 有一个叫做别名构造函数的东西。可以从shared_ptr&lt;A&gt;B* 创建shared_ptr&lt;B&gt;shared_ptr&lt;B&gt; 的析构函数将删除 A 对象,而不是 B

在您的情况下,您的 A 对象本身可以拥有一个 unique_ptr&lt;B&gt;,甚至是一个完全的 B 成员。

【讨论】:

    猜你喜欢
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 2018-07-28
    • 2013-05-19
    • 1970-01-01
    • 2013-06-17
    相关资源
    最近更新 更多