我的情况是我有一个类的层次结构: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个对象,但绝大多数都有空属性表(因为它们使用默认值)。查找性能比插入更重要,并且执行字符串哈希的性能可能可以忽略不计(我们无法测量它是否还没有写入它!)。
答案 0 :(得分: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
在自身旁边粘贴一个哈希,然后在哈希上查找(使用某种断言在调试中没有两个字符串哈希到相同的值 - 生日悖论使得发生的可能性远远超出人们的天真预期。这摆脱了单个管理器类(至少在发布时 - 在调试中,你有办法检测冲突。如果你的哈希是确定性的,调试中没有冲突可能意味着在发布时不会发生冲突)。 p>
具有适当可视化工具和一些运算符重载的boost::variant<enum1, enum2, enum3>
可以让您拥有多个独立的enum
。或者enum
以上的家庭酿造联盟,主要enum
表示哪个是有效的,并且在其上方有一个可视化工具,可以让您在整个地方拆分管理。在这两种情况下,您导出enum
的“类型”索引,然后导出enum
值 - 因此enum
的顺序必须是稳定的,并且其中的值每个enum
必须是稳定的,但不需要魔术整数。要检查是否相等,需要进行两个整数的链式比较,而不是一个(如果速度更快,您可以进行单个64位比较)。