使用std :: optional <int>与使用int?</int>一样高效

时间:2013-06-26 15:27:45

标签: c++ performance optional c++14 boost-optional

我有四/八树数据结构。我将一个单元格的子索引/ ptrs存储在一个数组中。数组中的每个位置代表一个孩子相对于其父母的位置,例如在2D中:

// _____________
// |     |     |
// |  2  |  3  |
// |_____|_____|
// |     |     |
// |  0  |  1  |
// |_____|_____|
// for each cell, 4 children are always stored in row-major order
std::vector<std::array<Integer,4>> children;

我知道最大子项数是Integer类型可以表示的值的子集。因此,我可以通过对-1使用Integer = intstd::numeric_limits<unsigned>::max() Integer = unsigned这样的“魔术”值来识别某个单元格是否遗漏了某个孩子。这是std::optional<Integer>无法承担的事情。

据我了解,魔法价值的使用是std::optional的存在理由之一。不过,我担心内循环中std::vector<std::optional<int>>的性能。

所以,

  • std::vector<std::optional<int>>的效果会不会比std::vector<int>更差? (我已经在对“不存在的”值进行比较了。)

  • 或者,是否可以优化std::optional的实施以提供与原始int相同的效果?怎么样?

在我的函数的返回类型和我的数据结构中的魔术值中混合使用std::optional听起来是一个非常糟糕的主意。我更喜欢保持一致,要么使用其中一个(至少在同一个上下文中)。虽然我可以重载与幻数进行比较的函数:

template<T> bool is_valid(const T& t) { 
  return /* comparison with magic value for t */; 
}

表示可选类型。

2 个答案:

答案 0 :(得分:14)

std::optional将需要额外的存储空间并将更少的值放入缓存中(看来你已经知道了这个原因)。

我不认为在数据结构内部存储与公共API公开的值不同的值是不正确的,只要内部表示对用户完全隐藏即可。

此外,我建议您将幻数分隔为一对inline转换函数。

编译器应该帮助您记住一致地使用转换函数,如果忘记则生成类型错误。您甚至可以在内部数据结构中为int使用精简结构包装器,以确保不存在隐式转换(或定义用户定义的转换)。

class CompressedOptionalUInt
{
    static const unsigned SENTINEL_MISSING = std::numeric_limits<unsigned>::max();
    unsigned value;

public:
    CompressedOptionalUInt(std::optional<unsigned> val) : value(!val? SENTINEL_MISSING: *val) {}
    operator std::optional<unsigned>() const { ... }
};

然后使用std::array<CompressedOptionalUInt>

将其变成模板,只需要为每种类型定义标记,应该非常简单。

答案 1 :(得分:3)

不,它效率不高。正如您从reference implementation所看到的,它必须存储,更新并检查额外的值。