本着“明智地选择容器”的精神,我感兴趣的是存储一个 或 no object,例如作为类中的成员。例如,如果被保持的对象计算成本昂贵并且应该以某种方式(或任何其他类型的“迟到”创建)进行缓存,则可能是这种情况。
明显的候选人是std::vector
和std::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
更改为具有“廉价”/不完整的构造函数,则可能返回无效对象。
带有向量的解决方案我更不喜欢语义,因为向量(或任何其他容器类型)可能给人的印象是可能不仅仅有一个对象。
现在再次考虑它,我认为我最喜欢指针解决方案,但是,仍然对它并不完全满意,并且想知道在这种情况下你是否知道任何最优雅的解决方案。
答案 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中的副本。