0

我有一种情况,我有一个类层次结构:Widget并且Doobry是继承自的对象类型Base(实际上有超过 2 种类型)。对象的每个实例都有一个属性列表。有一些属性是所有对象共有的,还有一些属性是特定于每个项目类型的。一个简单的实现可能如下所示:

enum PropertyType {
  COMMON_SIZE=0,              // first section: properties common to all
  COMMON_POSITION,
  ...
  WIDGET_PROPERTY_START=100,   // ensure enough space for expansion
  WIDGET_DONGLE_SIZE,
  WIDGET_TEXT,
  ...
  DOOBRY_PROPERTY_START=200
  DOOBRY_COLOUR
  ....
};

class Base {
public:
    Base();

    std::vector<std::pair<PropertyType, string>>  properties;
};

这实现了一个目标,在调试器中我可以看到映射到有意义名称的属性列表。但是它也有一些缺点:

  • 所有项目的属性都在一个标题中定义(不利于封装)
  • 如果我们向其中一个类添加更多属性,我们必须为每个类的起始位置选择一些任意数字,以便为将来的扩展留出足够的空间。

我的问题是是否有另一种方法可以实现这一目标。一种想法是我可以使用存储更大、查找速度更慢的字符串常量,但其优点是更容易使名称唯一,并且每种项目类型都可以定义自己的属性。

编辑:要求属性将被序列化,因此必须随着时间的推移保持稳定(即枚举不会改变)。可能有多达 1M 的对象,但绝大多数将有空的属性表(因为它们使用默认值)。查找性能比插入更重要,并且进行字符串散列的性能影响可能可以忽略不计(我们无法衡量它是否还没有写出来!)。

4

1 回答 1

1
struct UniqueTag {
  friend TagManager;
  char const* tag;
  UniqueTag( UniqueTag const& other):tag(other.tag) {}
  UniqueTag():tag(nullptr) {}; // being able to create the null tag is useful
  bool operator<( UniqueTag const& other )const{ return tag < other.tag; }
  bool operator==( UniqueTag const& other )const{ return tag == other.tag; }
  // do other operators
private:
  UniqueTag( char const* t ):tag(t) {}
};

#include <map> // or unordered_map for performance
class TagManager {
  std::map<std::string, UniqueTag> cache;
  std::vector< std::unique_ptr< char[] > > data;
public:
  TagManager() {};
  UniqueTag GetTag( std::string s ) {
    auto range = cache.equal_range(s);
    if (range.first != range.second) {
      return range.first->second;
    }
    std::unique_ptr< char[] > str( new char[ s.size()+1 ] );
    std::copy( s.begin(), s.end(), &str[0] );
    str[s.length()] = '\0';
    UniqueTag retval( str.get() );
    data.push_back( std::move(str) );
    if(s.length()==0) {
      retval = UniqueTag(); // empty string is null tag, so we don't have both!
    }
    cache.insert( range.first, make_pair( std::move(s), retval ) );
    return retval;
  }
};

单个TagManager维护一堆指向字符串的唯一指针。我们可以进行快速比较,因为我们在指针值上进行比较。从字符串转换为唯一标签之一很慢,并且隐含了单个标签管理器的反模式,但是......

替代版本包括在其UniqueTag旁边放置一个哈希,并在哈希上查找内容(通过某种断言在调试中没有两个字符串哈希到相同的值 - 生日悖论使这种情况发生的可能性远大于天真预计)。这摆脱了单个管理器类(至少在发布中 - 在调试中,您将有一种检测冲突的方法。如果您的哈希是确定性的,则调试中没有冲突可能意味着发布中没有冲突)。

带有适当的可视化工具和一些运算符重载的 Aboost::variant<enum1, enum2, enum3>会让您拥有多个独立enum的 s。enum或者es 上的自制联合,主节点enum表明哪个是有效的,在它上面有一个可视化器,可以让你在整个地方分散管理。在这两种情况下,您先导出 的“类型”的索引enum,然后导出enum值 - 因此enums 的顺序必须是稳定的,并且每个值中的值enum必须是稳定的,但不需要魔法整数。要检查相等性,需要一个两个整数链式比较而不是一个(如果这样更快,您可以将其破解为单个 64 位比较)。

于 2013-01-15T17:03:37.120 回答