我对共享指针没有太多专业知识,但是,这似乎是
weak_ptr
非常适合的用法。
在这种情况下,你只是很烦恼:
- 您想直接将
InputConsumer
作为ModelController
的成员使用,因为它是一种微不足道的所有权关系。
- 您被迫使用
shared_ptr
才能与weak_ptr
配合使用。
我认为,通过使用
shared_ptr
作为成员对象的
别名来解决这个问题。根据
C++.com的说法:
此外,shared_ptr对象可以共享指向另一个对象的指针的所有权同时指向另一个对象。这种能力称为别名(请参阅构造函数),通常用于指向拥有其所属对象的成员对象。
我从未尝试过,但这似乎适合你的情况:
- 将
InputConsumer
作为ModelController
的成员
- 为每个成员设置别名
shared_ptr
- 在
InputSender
中使用weak_ptr
引用它们
编辑
这里是一个完整的最小工作示例:
#include <iostream>
#include <memory>
using namespace std;
struct Foo
{
Foo() { cout << "constructing Foo\n"; }
~Foo() { cout << "destructing Foo\n"; }
};
struct Owner
{
Foo foo1;
Foo foo2;
shared_ptr<Owner> self;
struct Deleter
{
void operator() (Owner *) { cout << "pretend to delete Owner\n"; }
};
Owner() : self(this, Deleter()) { cout << "constructing Owner\n"; }
~Owner() { cout << "destructing Owner\n"; }
};
struct Observer
{
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()
{
Owner * owner = new Owner;
Observer observer(shared_ptr<Foo>(owner->self, &(owner->foo1)));
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
棘手的部分是能够创建一个指向owner->foo1
(对于foo2
也是同样)的weak_ptr
。为此,我们首先需要一个别名为owner->foo1
的shared_ptr
。这只能通过以下方式完成:
shared_ptr<Foo> alias(other_shared_ptr, &(owner->foo1));
其中,other_shared_ptr
是一个 shared_ptr<T>
,其生命周期至少与 owner->foo1
相同。为了实现这一点,使用一个也是 owner
成员的 shared_ptr<T>
是个好主意,因为它确保了生命周期相同。最后,我们需要一个有效的非空指针来给它,由于我们不想在堆上创建任何东西,所以我们必须使用一个现有的对象。this
是一个很好的选择,因为我们知道它是有效的,并且只有在其成员被销毁后才会被销毁。因此,我们的 other_shared_ptr
例如是:
shared_ptr<Owner> self(this);
然而,这意味着当
self
超出范围时,即在
owner
销毁期间,它将调用
delete this
。我们
不希望发生这种删除,否则
this
将被删除两次(在实践中是未定义的行为,可能会导致段错误)。因此,我们还向
self
的构造函数提供了一个Deleter,实际上不会删除任何内容。
其余代码应该很容易理解,有注释说明。
Owner
的shared_ptr<Foo> foo1_ptr
成员进行初始化,即Owner() : foo1_ptr(new Foo) {}
,然后直接使用Observer observer(owner->foo1_ptr)
,但这会在堆上创建数据,您可能希望避免这种情况。 - Boris Dalsteinnew
,因此也不应该调用delete
。但是您确实需要一个指向非空地址的shared_ptr
(以便能够使用weak_ptr
),并且默认情况下它会调用delete
,然后导致段错误。:-/ 感谢您在我的网站上发表评论 :-) - Boris Dalstein