引用类型返回函数:如何返回(可选)对象

时间:2019-01-17 11:34:57

标签: c++ reference

我有一个多线程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

考虑到我的列表无法在该索引处包含该对象,我引入了内存泄漏。

解决此问题的最佳解决方案是什么? 即使效率不高还是返回参考文献,我是否仍要退回副本?

3 个答案:

答案 0 :(得分:5)

您有多种选择:

  1. 如果“获取”将对象的所有权传递给调用者,请使用std::shared_ptr。这样,对象就不会超出范围。当然,呼叫者不会意识到它何时发生。
  2. 使用std::weak_ptr。含义与1.相同,但是可以重置ptr。在这种情况下,调用者可以检测到对象是否已删除。
  3. 按照注释中的建议使用std::optional,然后返回副本或参考。将引用类型用作可选参数不能避免删除对象的问题,因此引用也可能变为无效。复制会避免这种情况,但是如上所述,它可能太昂贵了。

通读这些行,您似乎建议呼叫者将在呼叫之后立即使用指针,并且使用时间有限。所以1.和2.是等效的,似乎符合您的需求。

有关更多详细信息,请参见this introduction to smart pointers

答案 1 :(得分:1)

如果要避免复制对象,只有两种可能的情况:

  1. m_list返回的getObject条目可以被另一个线程同时删除。如果您不事先复制该对象,则在getObject中您无法做任何事情来防止另一个线程突然具有引用/指针悬挂。但是,您可以将m_list的每个条目都设为std::shared_ptr<MyObject>并直接返回。内存管理将自动进行(但请注意shared_ptr的引用计数中的潜在开销以及死锁的可能性)。

  2. 您具有(或添加)了一些机制,以确保只有在当前没有其他线程持有指向它们的某些指针/引用的情况下,才可以从m_list中删除对象。这在很大程度上取决于您的算法,但可能例如可以将对象标记为仅删除,然后稍后在同步部分删除它们。

答案 2 :(得分:0)

您的问题似乎源于您的程序是多线程的-另一种前进的方式(对于原始指针或std::optional参考返回版本:这是唯一的前进方式,也许缺少完整的重新设计)是您需要将互斥锁公开到功能范围之外才能完成所需的操作。您可以通过多种方式完成此任务,但是,最简单的方法如下:

/*mutex lock*/
const MyObject& obj = globalClass.get(index);
/*do stuff with obj*/
/*mutex unlock*/