C++ 使用std::weak\u ptr的共享资源所有权
我想知道如何(使用C++11并希望使用向后(boost或TR1)兼容的智能指针类型)实现: 一个类实例(C++ 使用std::weak\u ptr的共享资源所有权,c++,c++11,shared-ptr,smart-pointers,weak-ptr,C++,C++11,Shared Ptr,Smart Pointers,Weak Ptr,我想知道如何(使用C++11并希望使用向后(boost或TR1)兼容的智能指针类型)实现: 一个类实例(ModelController)拥有一个资源(InputConsumer),而另一个组件(InputSender,在本例中是单例)可以访问它 模型是inputssender,它包含对inputsconsumers的引用列表,其中有许多引用 ModelController可能没有、一个或多个inputConsumer,也可能有多个ModelControllers。InputSender不知道 下
ModelController
)拥有一个资源(InputConsumer
),而另一个组件(InputSender
,在本例中是单例)可以访问它
模型是inputssender
,它包含对inputsconsumers
的引用列表,其中有许多引用
ModelController
可能没有、一个或多个inputConsumer
,也可能有多个ModelController
s。InputSender
不知道
下面是一个很好的方法:inputssender
可以跟踪分配给它的inputcummers
,这样它就可以自己发现单个inputcummers
是否有效
在我看来,弱\u ptr
非常适合此用途,因为它们的使用需要检查此条件
如果inputssender
停止跟踪其弱的\u ptr
参考,则不会发生任何坏情况,相应的inputsconsumer
s只会经历无线电静音
如果删除了ModelController
,或者ModelController
删除了一些InputConsumer
s,任何已注册的InputSender
s将在下次尝试访问它们时识别出它们不再存在,并可以进行清理,不需要发送消息或做任何事情
所以问题是,这是使用共享ptr
和弱ptr
的合适情况吗?我想知道shared\u ptr
是否完全合适,因为InputConsumer
s在概念上属于它们的ModelController
s,所以它们应该是成员变量。我不知道ModelController
只通过shared\u ptr
管理它们有多大意义。我不知道unique\u ptr
是否与弱\u ptr
一起工作。我应该只管理ModelController
的ctor/dtor中的共享\u ptr
吗
这可能也有一个众所周知的(对我来说不是!)设计模式,所以如果有人知道这样的事情,请告诉我。我在共享指针方面没有很多专业知识,但是是的,这似乎是对
弱\u ptr
的一个非常恰当的使用
在这种情况下,您只是对以下情况感到恼火:
inputcummer
s直接用作ModelController
s的成员,因为这是一个微不足道的所有权关系共享\u ptr
使其与弱\u ptr
一起工作共享\u ptr
作为成员对象的别名来解决。根据:
此外,共享的\u ptr对象可以共享指针的所有权
同时指向另一个物体。这个能力是
称为别名(参见构造函数),通常用于指向
成员对象,同时拥有它们所属的对象
我从未亲自做过,但这似乎适合你的情况:
- 拥有
sInputConsumer
s的成员ModelController
- 为他们每个人都有一个别名
共享\u ptr
- 使用
s在弱ptr
中引用它们InputSender
#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;
}
棘手的部分是能够创建一个到所有者->foo1
的弱ptr
(对于foo2
也是如此)。为此,我们首先需要一个shared_ptr
,它是owner->foo1
的别名。这只能通过以下方式实现:
shared_ptr<Foo> alias(other_shared_ptr, &(owner->foo1));
但是,这意味着当self
超出范围时,即在销毁owner
期间,它将调用删除此
。我们不希望发生此删除,否则此
将被删除两次(这是未定义的行为,实际上是SEGFULT)。因此,我们还向self
的构造函数提供了一个实际上不删除任何内容的删除器
代码的其余部分应该是带有注释的自解释代码。再完整一个工作代码段,显示std::weak_ptr dynamics,可能会有更多帮助。(我特别喜欢这个词)
#包括
#包括
#包括
类消息处理器{
};
类消息{
公众:
消息(std::shared\u ptr\u msg\u proc,int\u id){
proc_弱=标准::弱ptr(_msg_proc);
proc\u shared=\u msg\u proc;
id=_id;
}
std::弱ptr过程弱;
std::shared_ptr proc_shared;
int-id;
};
int main(){
std::shared_ptr proc(new MessageProcessor());
消息消息(proc,1);
//这里我们有两个共享的proc\u ptr参考:“proc”和“msg.proc\u shared”
//如预期的“msg.proc_弱未过期”
如果(!msg.proc_weak.expired())
std::这听起来真的很酷,但我现在还不清楚如何使用别名!你能发布一个小例子吗?谢谢!@StevenLu我以前从未使用过别名,所以我必须了解细节,事实上这比我预期的要复杂。无论如何,这是值得努力的,现在我很好地理解了它们,并且有了一个工作示例t我正在与您共享的内容(请参见编辑)。另一种方法是不使用这些别名,直接让共享的\u ptr foo1\u ptr
所有者的成员,用所有者()初始化:foo1\u ptr(新的Foo){}
,然后直接使用观察者(所有者->foo1\u ptr)
,但这会在堆上创建您可能希望避免的数据。我想知道是否有办法避免稍微不体面的伪删除程序。忽略d会造成什么样的破坏
shared_ptr<Foo> alias(other_shared_ptr, &(owner->foo1));
shared_ptr<Owner> self(this);
#include<iostream>
#include<memory>
#include<string>
class MessageProcessor{
};
class Message{
public:
Message(std::shared_ptr<MessageProcessor> _msg_proc, int _id){
proc_weak = std::weak_ptr<MessageProcessor>(_msg_proc);
proc_shared = _msg_proc;
id = _id;
}
std::weak_ptr<MessageProcessor> proc_weak;
std::shared_ptr<MessageProcessor> proc_shared;
int id;
};
int main(){
std::shared_ptr<MessageProcessor> proc(new MessageProcessor());
Message msg(proc,1);
// Here we have proc with 2 shared_ptr refs: 'proc' and 'msg.proc_shared'
// As expected 'msg.proc_weak is not expired'
if( !msg.proc_weak.expired() )
std::cout << "1) proc_weak is not EXPIRED. proc.use_count() == " << proc.use_count() << std::endl;
// make one of shared_ptr ref, point to other place
msg.proc_shared = std::shared_ptr<MessageProcessor>();
// there is still the 'proc' reference
if( !msg.proc_weak.expired() )
std::cout << "2) proc_weak is not EXPIRED (yet). proc.use_count() == " << proc.use_count() << std::endl;
// 'erase' the last reference
proc = std::shared_ptr<MessageProcessor>();
// Finally... There is no more refs in shared_pointer!
if( msg.proc_weak.expired() )
std::cout << "3) proc_weak has EXPIRED. proc.use_count() == " << proc.use_count() << std::endl;
return 0;
}