针对特殊情况,使用其他状态信息扩展基元类型



我正在寻找一种通过一些状态信息扩展int变量的方法,这些信息很少使用,大多数时候它只是重要的 int 值。这就是为什么我想避免使用带有其他布尔成员的结构。

相关的附加属性最多为 5 到 6 个附加属性,例如 NULL、UNDEFINED、NAN、MISSING 其中只有一个可以为真。

想法:

  • int 指针是针对一个附加属性执行此操作的一种方法:nullptr 是 int 变量可以采用的一个附加值。但在这种情况下,我不能拥有更多特殊的状态。

  • 另一种选择是使用一些我不希望使用的魔术值,例如UNDEFINED = std::numeric_limits<int>::min()MISSING = std::numeric_limits<int>::min()+1等。

:有没有更好的方法可以做到这一点(确实需要最少的额外内存(?

子问题:如果我可以在编译时确定值是否为例外情况,是否有一种好方法可以在不使用额外内存的情况下执行此操作?

最好的选择不是使用 int,而是使用其他类型 – 您使用int*的建议也属于这一类。当然,这种包装器类型可以重载各种运算符,以便于访问基础整数值。定义一个新类型(或利用现有的标准库类型(是内存的最佳术语,因为您可能只会将每个整数的大小加倍(例如,现在您可能有整数 + 枚举(由 int 或更小支持(+ 可能的填充(。根据您的整数大小,即使是指针也可能有更多的内存开销。

如果只有几个整数具有额外的状态,并且这些整数不会被复制或移动,那么您可以将状态存储在外部,从整数标识到状态的映射中。 即我们使用指向整数对象的指针作为键。对于具有额外状态的每个整数,此映射的内存开销将比替代方案高得多,但根据您的使用模式,这可能是最紧凑的解决方案。显然,这里存在内存泄漏的机会,因此您可能应该将整数包装在自定义类型中,该类型会在销毁时删除任何映射条目。大致是这样的:

enum class IntStatus { IS_NAN, IS_MISSING };
class IntWithExternalStatus {
public:
explicit IntWithExternalStatus(int x = 0) : m_value{x} {}
explicit IntWithExternalStatus(IntStatus s) : m_value{} { s_status.insert({this, s}); }
~IntWithExternalStatus() { m_status.erase(this); }
operator int& () { return m_value; }
operator int  () const { return m_value; }
bool is_valid() const { return s_status.find(this) == s_status.end(); }
bool is_nan() const {
auto it = s_status.find(this);
return it != s_status.end() && it->second == IntStatus::IS_NAN;
}
bool is_missing() const {
auto it = s_status.find(this);
return it != s_status.end() && it->second == IntStatus::IS_MISSING;
}
private:
static std::unordered_map<IntWithExternalStatus const*, IntStatus> s_status;
int m_value;
};

也许所有这些额外的类型都是不必要的过度复杂化。如果只有几个整数变量需要额外的状态,则为状态创建单独的变量可能是最简单的。例如:

int m_foo;
int m_bar;
IntStatus m_foo_status;
IntStatus m_bar_status;

由于对齐问题,这可能会导致比定义组合的 int-and-status 对象更紧凑的内存布局。

为您的状态使用特殊值是一种简单的解决方案,没有空间开销,但有一个巨大的缺点:对这些整数的任何算术都会擦除状态并产生虚假值。您将需要大量的运行时检查来防止这种情况,最好将其封装在单独的类型中。

关于编译时子问题,这取决于您对内存使用的定义。 例如,您可以使用模板元编程,根据编译时值选择intInvalidInt类型,其中 InvalidInt 是一种空对象模式。但是,这将为所有实例化的模板生成专用代码。特别是,使用状态整数的代码也必须进行模板化。如果同时有大量状态整数,并且所有状态都具有相同的状态,这可以减少总内存使用量,但在其他方案中不太可能有帮助。

最新更新