我有一个四/八叉树数据结构。我将一个单元格的子索引/ptrs 存储在一个数组中。数组中的每个位置都代表一个 child 相对于其 parent 的位置,例如二维:
// _____________
// | | |
// | 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
这样的“魔法”值来识别单元格是否缺少 child 。对于 Integer = int
, 或 std::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
在我的数据结构中我的函数和魔法值的返回类型听起来是一个非常糟糕的主意。我更喜欢保持一致并使用其中一个(至少在相同的上下文中)。虽然我可以重载执行与魔数(Magic Number)比较的函数:
template<T> bool is_valid(const T& t) {
return /* comparison with magic value for t */;
}
对于可选类型。
最佳答案
std::optional
将需要额外的存储空间并在缓存中放入更少的值(看来您已经知道这样做的原因)。
我认为在数据结构内部存储的值与公共(public) API 公开的值不同,只要内部表示对用户完全隐藏即可。
此外,我建议您将魔数(Magic Number)隔离为一对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>
.
将其制作成模板,只需为每种类型定义哨兵,应该非常简单。
关于c++ - 使用 std::optional<int> 是否与使用 int 一样有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17324286/