我想知道如何(使用C++ 11并希望与向后(提升或TR1)兼容的智能指针类型)实现:
一个类实例(ModelController
)拥有资源(InputConsumer
),而另一个组件(InputSender
在本例中为单例)可以访问它。
该模型是InputSender
,它包含一个对InputConsumers
的引用列表,其中将有很多引用。ModelController
可能没有,只有一个或很多InputConsumers
,并且可能有很多ModelController
。 InputSender
无法识别。
这是件好事:InputSender
跟踪分配给它的InputConsumers
的一种方式,这样它就可以自己找出各个InputConsumers
是否有效。
在我看来,weak_ptr
非常适合此目的,因为使用它们需要检查此条件。
如果InputSender
停止跟踪其任何weak_ptr
引用,则不会发生任何不良情况,相应的InputConsumer
只会经历 radio 静默状态。
如果删除了ModelController
,或者如果ModelController
删除了其某些InputConsumer
,则已向其注册的任何InputSender
都会在下次尝试访问它们时识别出它们不再存在,并且可以清理而无需使用发送消息或执行任何操作。
所以问题是,这是否适合使用shared_ptr
和weak_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:我自己从未做过,但这似乎适合您的情况:
InputConsumer
的ModelController
成员shared_ptr
别名InputSender
在weak_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_ptr
到owner->foo1
(与foo2
相同)。为此,我们首先需要一个shared_ptr
,它是owner->foo1
的别名。这只能通过以下方式完成:shared_ptr<Foo> alias(other_shared_ptr, &(owner->foo1));
其中
other_shared_ptr
是shared_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,它实际上并不删除任何内容。代码的其余部分应使用注释不言自明。