[英]How can I guarantee an object's lifespan matches the duration of a member function?
I've been making use of callbacks to reduce coupling between some C++ classes. 我一直在使用回调来减少某些C ++类之间的耦合。 To define terms: I'll call the class making the callbacks the caller, and the class receiving the callback the callee.
定义术语:我将调用回调的类称为调用者,将接收回调的类称为被调用者。 Typically (but not necessarily), the callee will own the caller.
通常(但不是必须),被呼叫者将拥有呼叫者。 By design, the caller has no knowledge of the callee.
通过设计,呼叫者不了解被呼叫者。
I'm running into an issue relating to the lifespan of the caller object: It has no guarantee that it will still be alive after making any arbitrary callback. 我遇到了一个与调用者对象的生命周期有关的问题:它不能保证在进行任何任意回调后它仍然会存在。 Take this basic example:
举个基本的例子:
void caller::f()
{
/* Some work */
if (...)
{
/* [1] Execute callback */
_callee->callback(this);
}
/* [2] Some more work */
}
Say that the callee has dynamically allocated the caller, and has registered for the callback specifically to wait for a certain condition to occur. 假设被呼叫者已经动态分配了呼叫者,并已专门为回调注册以等待特定条件的发生。 When it does, the callee will delete the caller from within the callback at [1].
完成后,被叫方将从[1]的回调中删除该呼叫者。 If that's the case, control will then return to caller::f, but
this
will have been deleted, and any code at [2] will more than likely crash. 如果是这样的情况下,控制可能会返回主调::女,但
this
已经被删除了,并且在任何代码[2]将很可能崩溃。
In the general case, the caller can't assume anything about the callee. 在一般情况下,呼叫者无法承担有关被呼叫者的任何事情。 It doesn't know if the callee owns
this
, or if it might deallocate this
, so I would need some general means of preventing deallocation for the scope of the caller's member function. 它不知道被调用方是否拥有
this
,或者它是否可能取消分配this
,因此我将需要一些常规方法来防止在调用方成员函数的作用域内重新分配。
I believe a possible solution revolves around boost::shared_ptrs
and enable_shared_from_this
, though I've never used it. 我相信可能的解决方案围绕
boost::shared_ptrs
和enable_shared_from_this
,尽管我从未使用过。 Since these callbacks are running very frequently (40+ times per second) on mobile devices with limited processing power, I'm also worried about the overhead of creating and passing out that many shared_ptrs
. 由于这些回调在处理能力有限的移动设备上非常频繁地运行(每秒40次以上),因此我也担心创建和
shared_ptrs
许多shared_ptrs
的开销。
Delegation is a pretty common pattern in Objective-C. 委派是Objective-C中非常常见的模式。 I'm far less familiar with common C++ design patterns.
我对常见的C ++设计模式不太熟悉。 Is there any quick-and-easy fix for this issue?
是否有解决此问题的简便方法? If not, how would this design typically be accomplished in C++?
如果没有,通常如何在C ++中完成这种设计?
When the callee delete
s caller, caller's destructor is called. 当被调用方
delete
s调用方时,将调用调用方的析构函数。 It is there that you should make sure f
has finished. 在此应确保
f
已完成。
I am guessing f
is a thread, so easiest solution would be: 我猜
f
是一个线程,所以最简单的解决方案是:
thread: 线:
running = true;
while (!must_exit)
/* do something */
destuctor: 解构器:
thread->must_exit = true;
while (thread->running)
sleep(a_little);
/* continue with destruction */
If f
is not a thread, the same principle can apply where f
makes its object (and through that its destructor) know when it is running and when not. 如果
f
不是线程,则在f
使其对象(并通过其析构函数)知道何时运行以及何时不运行的情况下,可以应用相同的原理。
If you don't want to go with a destructor approach, you can still implement this functionality through a function that the callee calls, telling f
to never run again and wait until it stops. 如果您不希望使用析构方法,则仍可以通过被调用方调用的函数来实现此功能,告诉
f
再也不要运行,直到它停止为止。 Then the callee continues with deletion of caller. 然后,被叫方继续删除呼叫者。
So something like this: 所以像这样:
void caller::f()
{
if (being_deleted)
return;
running = true;
/* Some work */
if (...)
{
/* [1] Execute callback */
_callee->callback(this);
}
/* [2] Some more work */
running = false;
}
void caller::make_f_stop()
{
being_deleted = true;
while (running)
sleep(a_little);
}
Go ahead and use the shared pointer, though if possible use std::shared_ptr
instead of boost::shared_ptr
. 继续并使用共享指针,尽管可能的话,请使用
std::shared_ptr
而不是boost::shared_ptr
。 It's in the (current) standard library, so no need to add an unnecessary boost dependency. 它在(当前)标准库中,因此无需添加不必要的boost依赖项。 If you're already using boost, then that's fine too.
如果您已经在使用boost,那也很好。
You didn't specify what sort of mobile device you're talking about, but the processors in modern smartphones run at hundreds or thousands of megahertz, and even low-power phones often run Java programs (with garbage collection) just fine. 您没有指定要谈论的移动设备类型,但是现代智能手机中的处理器运行速度高达数百或数千兆赫兹,甚至低功率手机也经常运行Java程序(带有垃圾回收)就可以了。 Shared pointers are basically reference counted.
共享指针基本上是引用计数。 It's not a resource-intensive activity.
这不是资源密集型活动。
If your device is able to actually run the callback more than 40 times per second, I doubt it will have any trouble with shared pointers. 如果您的设备每秒可以实际运行回调超过40次,那么我怀疑共享指针是否会带来麻烦。 Don't prematurely optimize for execution speed.
不要过早地优化执行速度。 DO prematurely optimize for safety and sanity.
请过早优化安全性和卫生性。
The usual way of bypassing code that you can't execute anymore is to throw an exception. 绕过不再执行的代码的通常方法是引发异常。 This should be done by the callee at the point where it would normally return to the caller, after it has deleted the caller.
被呼叫者应在删除呼叫者之后通常返回到呼叫者的位置进行此操作。 The exception would be caught in the caller code at the end of the function.
该函数的末尾将在调用者代码中捕获该异常。
I can't say I like this solution, but I think that stems from the unusual situation of the callee owning the caller. 我不能说我喜欢这种解决方案,但我认为这是由于被呼叫者拥有呼叫者的情况异常。
I don't know how smart pointers would help since there's nobody to own the second copy of the pointer. 我不知道智能指针将如何提供帮助,因为没有人拥有指针的第二个副本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.