代码之家  ›  专栏  ›  技术社区  ›  Programmer

创建映射到外部定义的名称的结构行

  •  2
  • Programmer  · 技术社区  · 7 年前

    我们的课程如下:

    NamesOfData GetNamesOfData()
    {
        NamesOfData names =
        {
            "AAA",
            "BBB"
        };
      return names;
    }
    

    现在我有了一个结构,它必须有上面提到的名称以及其他字段:

    struct A
    {
        std::string name;
        ...other fields...;
    };
    

    struct A Data [] =
    {
         "AAA",.......;
         "BBB", ......;
    };
    

    但问题是,我需要确保struct中的名称和外部定义的名称的完整性——如果在任何地方修改名称,这些名称随时都可能被破坏。

    是否有一种方法可以克服上述问题,或者更确切地说,将名称集中起来,但很容易由两个地方映射?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Scheff's Cat    7 年前

    我之前在评论中写道:

    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

    注:

    1. std::unordered_map std::map 目录 std::less 在里面 标准::地图

    2. 事实上,名称(原子)只是添加的——它们在销毁原子之前是故意不删除的 AtomTable Atom