在c ++中存储一个或没有对象的首选方法是什么?

时间:2017-01-09 22:25:30

标签: c++ c++11 stl

本着“明智地选择容器”的精神,我感兴趣的是存储一个 no object,例如作为类中的成员。例如,如果被保持的对象计算成本昂贵并且应该以某种方式(或任何其他类型的“迟到”创建)进行缓存,则可能是这种情况。

明显的候选人是std::vectorstd::unique_ptr,例如:

class object_t;
class foo_t {
  std::unique_ptr<object_t> m_cache;
  public:
    object_t getObject() {
      if( not m_cache ) {
        m_cache.reset(new object_t()); // object creation is expensive
      }
      return object_t(*m_cache);
    }
};

和矢量(或几乎任何其他容器)类似:

class object_t;
class foo_t {
  std::vector<object_t> m_cache;
  public:
    object_t getObject() {
      if( m_cache.empty() ) {
        m_cache.push_back(object_t()); // object creation is expensive
      }
      return m_cache.front();
    }
};

当然,仍然有可能有一些布尔变量,它保存对象的状态:

class object_t;
class foo_t {
  bool cache_healthy;
  object_t m_cache;
  public:
    foo_t() : cache_healthy(false), m_cache() {}
    object_t getObject() {
      if( not cache_healthy ) {
        m_cache = object_t();
        cache_healthy = true;
      }
      return m_cache;
    }
    /* do other things that might set cache_healthy to false. */
};

从三个示例中,我喜欢最后一个示例,因为它要么创建对象两次,要么,如果我将object_t更改为具有“廉价”/不完整的构造函数,则可能返回无效对象。

带有向量的解决方案我更不喜欢语义,因为向量(或任何其他容器类型)可能给人的印象是可能不仅仅有一个对象。

现在再次考虑它,我认为我最喜欢指针解决方案,但是,仍然对它并不完全满意,并且想知道在这种情况下你是否知道任何最优雅的解决方案。

1 个答案:

答案 0 :(得分:1)

“显而易见”的解决方案是使用boost::optional或(在C ++ 17中)std::optional

这样的实现可能如下所示:

template <typename T>
class optional
{
public:
    optional() : m_isset(false) {}

    template <typename ...Args>
    optional(Args... args) {
        m_isset = true;
        new (&m_data[0]) optional { args... };
    }

    // overload operator-> and operator* by reinterpret_casting m_data, throwing exceptions if isset == false

private:
    bool m_isset;
    char m_data[sizeof(T)];
}

您的解决方案的缺点是在1和2中不需要堆分配,并且依赖于3中的副本。