我有一个多线程C++应用程序,它可以从任何线程调用类似下面的函数,从列表/向量中获取一个Object.
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();
Run Code Online (Sandbox Code Playgroud)
注意:这里的范围是通过引用,值或指针来理解与函数返回相关的一些最佳实践,因此请原谅一些伪代码或缺少声明(我使用锁定/解锁,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();
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是MyObject返回的object()是一个足够大的对象,返回副本效率不高.
最后,我想返回对该对象的引用(更好的const引用):
const MyObject& GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return *m_list[index];
else{
MyObject* obj = new MyObject();
return *obj ;
}
}
Run Code Online (Sandbox Code Playgroud)
考虑到我的列表无法在该索引处加入对象,我引入了内存泄漏.
处理这个问题的最佳解决方案是什么?即使效率较低,或者在返回引用时我是否缺少某些内容,我是否必须退回复制副本?
你有多种选择:
std::shared_ptrif"Get"将对象的拥有权传递给调用者.这样对象就不会超出范围.当然,调用者在发生这种情况时并不知道.std::weak_ptr.这与1具有相同的含义,但ptr可以重置.在这种情况下,调用者可以检测对象是否被删除.std::optional按照评论中的建议使用,并返回副本或引用.使用引用类型作为可选参数不能避免对象被删除的问题,因此引用也可能变得无效.副本可以避免这种情况,但它可能过于昂贵,如上所述.通过这些行读取,您似乎建议调用者在调用后立即使用指针,并在有限的时间内使用.所以1.和2.是等价的,似乎符合你的需要.
有关更多详细信息,请参阅智能指针的介绍.