我想知道如何(使用C++ 11并希望与向后(提升或TR1)兼容的智能指针类型)实现:

一个类实例(ModelController)拥有资源(InputConsumer),而另一个组件(InputSender在本例中为单例)可以访问它。

该模型是InputSender,它包含一个对InputConsumers的引用列表,其中将有很多引用。
ModelController可能没有,只有一个或很多InputConsumers,并且可能有很多ModelControllerInputSender无法识别。

这是件好事:InputSender跟踪分配给它的InputConsumers的一种方式,这样它就可以自己找出各个InputConsumers是否有效。

在我看来,weak_ptr非常适合此目的,因为使用它们需要检查此条件。

如果InputSender停止跟踪其任何weak_ptr引用,则不会发生任何不良情况,相应的InputConsumer只会经历 radio 静默状态。

如果删除了ModelController,或者如果ModelController删除了其某些InputConsumer,则已向其注册的任何InputSender都会在下次尝试访问它们时识别出它们不再存在,并且可以清理而无需使用发送消息或执行任何操作。

所以问题是,这是否适合使用shared_ptrweak_ptr?我想知道shared_ptr是否完全合适,因为InputConsumer在概念上由其ModelController拥有,因此它们应该是成员变量。我不知道ModelController仅通过shared_ptr管理它们有多大意义。我不知道unique_ptr是否可以与weak_ptr一起使用。我应该只在shared_ptr的ctor / dtor中管理ModelController吗?

可能还会有一个众所周知的(对我而言不是!)设计模式,因此,如果有人知道这种情况,请告诉我。

最佳答案

我在共享指针方面没有很多专业知识,但是是的,这似乎是weak_ptr的非常合适的用法。

在这种情况下,您会感到烦恼:

  • 您想直接将InputConsumer用作ModelController的成员,因为它的所有权关系微不足道。
  • 您被迫使用shared_ptr使其与weak_ptr一起使用。

  • 我认为这可以通过使用shared_ptr作为成员对象的别名来解决。根据C++.com:



    我自己从未做过,但这似乎适合您的情况:
  • 具有InputConsumerModelController成员
  • 每个别名都有一个shared_ptr别名
  • 使用InputSenderweak_ptr中引用它们

  • 编辑

    这是一个完整的最小工作示例:
    #include <iostream>
    #include <memory>
    
    using namespace std;
    
    // A class to try our smart pointers on
    struct Foo
    {
        Foo() { cout << "constructing Foo\n"; }
        ~Foo() { cout << "destructing Foo\n"; }
    };
    
    // A class that owns some Foo as members
    struct Owner
    {
        // The actual members
        Foo foo1;
        Foo foo2;
    
        // A fake shared pointer whose purpose is:
        //   1) to be of type shared_ptr<>
        //   2) to have the same lifetime as foo1 and foo2
        shared_ptr<Owner> self;
    
        // A fake deleter that actually deletes nothing
        struct Deleter
        {
            void operator() (Owner *) { cout << "pretend to delete Owner\n"; }
        };
    
        Owner() : self(this, Deleter()) { cout << "constructing Owner\n"; }
        ~Owner()                        { cout << "destructing Owner\n"; }
    };
    
    // A class that holds a reference to a Foo
    struct Observer
    {
        // A reference to a Foo, as a weak pointer
        weak_ptr<Foo> foo_ptr;
    
        Observer(const shared_ptr<Foo> & foo_ptr) : foo_ptr(foo_ptr)
        {
            cout << "constructing Observer\n";
        }
        ~Observer() { cout << "destructing Observer\n"; }
    
        void check()
        {
            if(foo_ptr.expired())
                cout << "foo expired\n";
            else
                cout << "foo still exists\n";
        }
    };
    
    int main()
    {
        // Create Owner, and hence foo1 and foo2
        Owner * owner = new Owner;
    
        // Create an observer, passing an alias of &(owner->foo1) to ctor
        Observer observer(shared_ptr<Foo>(owner->self, &(owner->foo1)));
    
        // Try to access owner->foo1 from observer
        observer.check();
        delete owner;
        observer.check();
    
        return 0;
    }
    

    它打印:
    constructing Foo
    constructing Foo
    constructing Owner
    constructing Observer
    foo still exists
    destructing Owner
    pretend to delete Owner
    destructing Foo
    destructing Foo
    foo expired
    destructing Observer
    

    棘手的部分是能够创建一个weak_ptrowner->foo1(与foo2相同)。为此,我们首先需要一个shared_ptr,它是owner->foo1的别名。这只能通过以下方式完成:
    shared_ptr<Foo> alias(other_shared_ptr, &(owner->foo1));
    

    其中other_shared_ptrshared_ptr<T>,其生存期至少与owner->foo1之一相同。为此,使用也是shared_ptr<T>成员的owner是一个好主意,因为它可以确保生存期相同。最后,我们需要一个有效的非null指针来赋予它,并且由于我们不想在堆上创建任何东西,因此必须使用现有的对象。 this是一个很好的候选者,因为我们知道它是有效的并且只有在其成员被销毁后才被销毁。因此,我们的other_shared_ptr例如:
    shared_ptr<Owner> self(this);
    

    但是,这意味着当self超出范围时,即在owner销毁期间,它将调用delete this。我们不希望发生这种删除,否则this将被删除两次(这是未定义的行为,实际上是段错误)。因此,我们还向self的构造函数提供了一个Deleter,它实际上并不删除任何内容。

    代码的其余部分应使用注释不言自明。

    09-10 04:29
    查看更多