我之前在评论中写道:
XAtom
是的。这已经是几十年前的事了,但我仍然喜欢atom表的概念,并在适当的时候使用它),但编译器中的符号表可能会做类似的事情:
std::vector<const char*>
用于唯一存储绑定到的名称
std::map<const char *, size_t>
我用
const char*
而不是
std::string
std::vector::resize()
可能会复制字符串并使我用于反向映射的C字符串地址无效(以防止重复存储字符串)。
因此,OP
struct A
可以引用此表中的索引。是否允许重复的名称是此atom表之外的设计决策。
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#include <vector>
// atom table to store unique strings
class AtomTable {
private:
// storage of strings (mapping of indices to strings)
std::vector<const char*> _names;
// predicate for lexicographical order of names
struct LessName {
bool operator()(const char *name1, const char *name2) const
{
return strcmp(name1, name2) < 0;
}
};
typedef std::map<const char*, size_t, LessName> Map;
// mapping of strings to indices
Map _map;
static const char* strdup(const std::string &name)
{
char *name2 = new char[name.size() + 1];
strcpy(name2, name.c_str());
return name2;
}
public:
AtomTable() = default;
~AtomTable()
{
_map.clear();
for (const char *&name : _names) delete[] name;
}
AtomTable(const AtomTable&) = delete; // important to disable this
AtomTable& operator=(const AtomTable&) = delete; // important to disable this
size_t find(const std::string &name) const
{
Map::const_iterator iter = _map.find(name.c_str());
return iter != _map.end()
? iter->second // index of name in table
: (size_t)-1; // invalid index
}
size_t get(const std::string &name)
{
size_t i = find(name);
if (i < _names.size()) return i;
// not yet in table -> add
i = _names.size();
_names.push_back(strdup(name));
_map[_names.back()] = i;
return i;
}
const char* get(size_t i) const
{
return _names[i];
}
size_t size() const { return _names.size(); }
};
// a singleton atom table
static AtomTable& atomTable()
{
// like learnt from Meyer:
// https://stackoverflow.com/q/1661529/7478597
static AtomTable atomTable;
return atomTable;
}
// a sample structure
struct A {
size_t iName;
int payload;
A(const std::string &name, int payload):
iName(atomTable().get(name)), payload(payload)
{ }
~A() = default;
A(const A&) = default;
A& operator=(const A&) = default;
};
std::ostream& operator<<(std::ostream &out, const A &a)
{
return out << "A { name: '" << atomTable().get(a.iName)
<< "' (" << a.iName << "), payload: " << a.payload << " }";
}
int main()
{
std::vector<A> aTable = {
{ "first", 1 },
{ "second", 2 },
{ "third", 3 },
{ "first", 4 }
};
size_t i = 0; for (const A &a : aTable) {
std::cout << i << ".: " << a << '\n'; ++i;
}
std::cout
<< "About Atom Table:\n"
<< "Number of entries: " << atomTable().size() << '\n'
<< "'first' in table?: "
<< (atomTable().find("first") < atomTable().size() ? "yes" : "no")
<< '\n'
<< "'other' in table?: "
<< (atomTable().find("other") < atomTable().size() ? "yes" : "no")
<< '\n';
return 0;
}
输出:
0.: A { name: 'first' (0), payload: 1 }
1.: A { name: 'second' (1), payload: 2 }
2.: A { name: 'third' (2), payload: 3 }
3.: A { name: 'first' (0), payload: 4 }
About Atom Table:
Number of entries: 3
'first' in table?: yes
'other' in table?: no
Live Demon on coliru
注:
-
-
std::unordered_map
std::map
目录
std::less
在里面
标准::地图
-
事实上,名称(原子)只是添加的——它们在销毁原子之前是故意不删除的
AtomTable
Atom