简体   繁体   English

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

[英]What is the preferred way to store one or no object in c++?

In the spirit of "choose your containers wisely", I am interested in what is the best way to store either exactly one or no object, for example as a member in a class. 本着“明智地选择容器”的精神,我对什么是存储一个 存储任何对象(例如,作为类的成员)的最佳方法感兴趣。 This could be the case, eg, if the object being held is expensive to calculate and should be cached in some way (or any other type of "late" creation). 例如,如果所保存的对象的计算成本很高并且应以某种方式(或任何其他类型的“后期”创建)进行缓存,则可能是这种情况。

The obvious candidates are std::vector and std::unique_ptr , for example: 显而易见的候选对象是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);
    }
};

and similarly with vector (or almost any other container): 并与vector(或几乎任何其他容器)类似:

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();
    }
};

Of course, there is still the possibility to have some boolean variable, which holds the state of the object: 当然,仍然可以使用一些布尔变量来保存对象的状态:

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. */
};

From the three examples, I like the last one the less, because it either creates the object twice, or, if I change object_t to have a "cheap" / incomplete constructor, might return a invalid object. 在这三个示例中,我不太喜欢最后一个示例,因为它要么创建两次对象,要么如果我将object_t更改为具有“便宜” /不完整的构造函数,则可能会返回无效的对象。

The solution with the vector I dislike more semantically, because a vector (or any other container type) might give the impression that there might be more than just one object. 我不喜欢使用向量的解决方案,因为向量(或任何其他容器类型)可能给人的印象是可能存在多个对象。

Now thinking of it again, I think I like the pointer solution most, however, still am not entirely happy with it and would like to hear if you know of any solution that is the most elegant in this case. 现在再次考虑它,我想我最喜欢指针解决方案,但是仍然不完全满意,并且想听听您是否知道在这种情况下最优雅的解决方案。

The "obvious" solution is using boost::optional or (in C++17) std::optional . “显而易见”的解决方案是使用boost::optional或(在C ++ 17中) std::optional

An implementation of something like this could look like the following: 这样的实现可能如下所示:

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)];
}

The disadvantages of your solutions are unneeded heap allocation in 1 and 2 and reliance on a copy in 3. 解决方案的缺点是在1和2中不需要分配堆,而在3中依赖副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM