我有一个多线程C ++应用程序,可以从任何线程调用如下函数,以从列表/向量中获取对象。
class GlobalClass{
public:
MyObject* GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return m_list[index];
else
return 0;
}
List<MyObject*> m_list;
};
//Thread function
MyObject* obj = globalClass->getObject(0);
if (!obj) return;
obj->doSomething();
注意:这里的范围是通过引用,值或指针来了解与函数返回相关的一些最佳实践,因此可以原谅一些伪代码或缺少的声明(我使用锁定/解锁,{{1} }是全局单例,等等。)
这里的问题是,如果在GlobalClass
内部删除了该索引处的MyObject
,则在某个时刻我正在使用错误的指针(GlobalClass
)。
所以我正在考虑退还该物品的副本:
obj
这里的问题是返回的对象( MyObject GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return MyObject(*m_list[index]);
else
return MyObject();
}
)足够大,因此返回副本效率不高。
最后,我想返回对该对象的引用(最好是const引用):
MyObject
考虑到我的列表无法在该索引处包含该对象,我引入了内存泄漏。
解决此问题的最佳解决方案是什么? 即使效率不高还是返回参考文献,我是否仍要退回副本?
答案 0 :(得分:5)
您有多种选择:
std::shared_ptr
。这样,对象就不会超出范围。当然,呼叫者不会意识到它何时发生。 std::weak_ptr
。含义与1.相同,但是可以重置ptr。在这种情况下,调用者可以检测到对象是否已删除。std::optional
,然后返回副本或参考。将引用类型用作可选参数不能避免删除对象的问题,因此引用也可能变为无效。复制会避免这种情况,但是如上所述,它可能太昂贵了。通读这些行,您似乎建议呼叫者将在呼叫之后立即使用指针,并且使用时间有限。所以1.和2.是等效的,似乎符合您的需求。
有关更多详细信息,请参见this introduction to smart pointers。
答案 1 :(得分:1)
如果要避免复制对象,只有两种可能的情况:
由m_list
返回的getObject
条目可以被另一个线程同时删除。如果您不事先复制该对象,则在getObject
中您无法做任何事情来防止另一个线程突然具有引用/指针悬挂。但是,您可以将m_list
的每个条目都设为std::shared_ptr<MyObject>
并直接返回。内存管理将自动进行(但请注意shared_ptr
的引用计数中的潜在开销以及死锁的可能性)。
您具有(或添加)了一些机制,以确保只有在当前没有其他线程持有指向它们的某些指针/引用的情况下,才可以从m_list
中删除对象。这在很大程度上取决于您的算法,但可能例如可以将对象标记为仅删除,然后稍后在同步部分删除它们。
答案 2 :(得分:0)
您的问题似乎源于您的程序是多线程的-另一种前进的方式(对于原始指针或std::optional
参考返回版本:这是唯一的前进方式,也许缺少完整的重新设计)是您需要将互斥锁公开到功能范围之外才能完成所需的操作。您可以通过多种方式完成此任务,但是,最简单的方法如下:
/*mutex lock*/
const MyObject& obj = globalClass.get(index);
/*do stuff with obj*/
/*mutex unlock*/