C++ 如何使用类体内的键/值创建一次映射(不是每次调用类中的函数时)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3113979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:05:48  来源:igfitidea点击:

How to create map with keys/values inside class body once (not each time functions from class are called)

c++classstaticmapping

提问by user360872

I would like to create C++ class which would allow to return value by given key from map, and key by given value. I would like also to keep my predefined map in class content. Methods for getting value or key would be static. How to predefine map statically to prevent creating map each time I call getValue(str) function?

我想创建 C++ 类,它允许通过映射中的给定键返回值,并通过给定值返回键。我还想在课堂内容中保留我的预定义地图。获取值或键的方法是静态的。如何静态预定义地图以防止每次调用 getValue(str) 函数时创建地图?

class Mapping
{
  static map<string, string> x;

  Mapping::Mapping()
  {
    x["a"] = "one";
    x["b"] = "two";
    x["c"] = "three";
  }

  string getValue(string key)
  {
    return x[key];
  }

  string getKey(string value)
  {
    map<string, string>::const_iterator it;

    for (it = x.begin(); it < x.end(); ++it)
      if (it->second == value)
        return it->first;

    return "";
  }
};

string other_func(string str)
{
  return Mapping.getValue(str);  // I don't want to do:  new Mapping().getValue(str);
}

Function other_func is called often so I would prefer to use map which is created only once (not each time when other_func is called). Do I have to create instance of Mapping in main() and then use it in other_func (return instance.getValue(str)) or is it possible to define map in class body and use it by static functions?

函数 other_func 经常被调用,所以我更喜欢使用只创建一次的映射(不是每次调用 other_func 时)。我是否必须在 main() 中创建 Mapping 的实例,然后在 other_func (返回 instance.getValue(str))中使用它,还是可以在类主体中定义 map 并通过静态函数使用它?

回答by Martin York

Is this what you want?

这是你想要的吗?

#include <map>
#include <string>

class Mapping
{
    private:
        // Internally we use a map.
        // But typedef the class so it is easy to refer too.
        // Also if you change the type you only need to do it in one place.
        typedef std::map<std::string, std::string>  MyMap;
        MyMap   x; // The data store.

        // The only copy of the map
        // I dont see any way of modifying so declare it const (unless you want to modify it)
        static const Mapping myMap;

        // Make the constructor private.
        // This class is going to hold the only copy.
        Mapping()
        {
            x["a"]  =       "one";
            x["b"]  =       "two";
            x["c"]  =       "three";
        }


    public:
        // Public interface.
        //    Returns a const reference to the value.
        //    The interface use static methods (means we dont need an instance)
        //    Internally we refer to the only instance.
        static std::string const& getValue(std::string const& value)
        {
            // Use find rather than operator[].
            // This way you dont go inserting garbage into your data store.
            // Also it allows the data store to be const (as operator may modify the data store
            // if the value is not found).

            MyMap::const_iterator   find    = myMap.x.find(value);
            if (find != myMap.x.end())
            {
                // If we find it return the value.
                return find->second;
            }

            // What happens when we don;t find anything.
            // Your original code created a garbage entry and returned that.
            // Could throw an exception or return a temporary reference.
            // Maybe ->  throw int(1);
            return "";
        }

};

回答by Jerry Coffin

First of all, you might want to look up Boost::MultiIndexand/or Boost::bimap. Either will probably help a bit with your situation of wanting to use either one of the paired items to look up the other (bimap is more directly what you want, but if you might need to add a third, fourth, etc. key, then MultiIndex may work better). Alternatively, you might want to just use a pair of sorted vectors. For situations like this where the data remains constant after it's been filled in, these will typically allow faster searching and consume less memory.

首先,您可能需要查找Boost::MultiIndex和/或Boost::bimap。对于您想要使用配对项目中的任何一个来查找另一个的情况,要么可能会有所帮助(bimap 更直接是您想要的,但如果您可能需要添加第三个、第四个等键,那么MultiIndex 可能效果更好)。或者,您可能只想使用一对已排序的向量。对于这种数据在填充后保持不变的情况,这些通常会允许更快的搜索并消耗更少的内存。

From there, (even though you don't have to make it explicit) you can handle initialization of the map object itself a bit like a singleton -- put the data in the first time it's needed, and from then on just use it:

从那里,(即使您不必明确表示)您可以像单例一样处理地图对象本身的初始化——在第一次需要时将数据放入,然后就可以使用它:

class Mapping { 
    static map<string, string> x;
    static bool inited;
public:
    Mapping() { 
        if (!inited) { 
            x["a"] = "one";
            x["b"] = "two";
            x["c"] = "three";
            inited = true;
        }
    }
    string getValue(string const &key) { return x[key]; }
};

// This initialization is redundant, but being explicit doesn't hurt.
bool Mapping::inited = false; 
map<string, string> Mapping::x;

With this your some_funccould look something like this:

有了这个,你some_func可能看起来像这样:

string some_func(string const &input) {
    return Mapping().getValue(input);
}

This still has a littleoverhead compared to pre-creating and using an object, but it should be a lot less than re-creating and re-initializing the map (or whatever) every time.

与预先创建和使用对象相比,这仍然有一些开销,但它应该比每次重新创建和重新初始化地图(或其他)要少得多。

回答by DanDan

If you are looking up the value from the key a lot, you will find it easier and more efficient to maintain a second map in parallel with the first.

如果您经常从键中查找值,您会发现与第一个映射并行维护第二个映射更容易、更有效。

回答by Zoli

You don't need to create a static map especially if you ever want to create multiple Mappingobjects. You can create the object in main() where you need it, and pass it around by reference, as in:

您不需要创建静态地图,尤其是当您想要创建多个Mapping对象时。您可以在 main() 中需要它的地方创建对象,并通过引用传递它,如下所示:

string other_func(Mapping &mymap, string str)
{
   return mymap.getValue(str);
}

Of course this raises questions about efficiency, with lots of strings being copied, so you might want to just call getValuedirectly without the extra overhead of calling other_func.

当然,这会引发关于效率的问题,因为有很多strings 被复制,因此您可能只想getValue直接调用,而无需额外的调用开销other_func.

Also, if you know anything about the Boost libraries, then you might want to read up on Boost.Bimap which is sort of what you are implementing here.

此外,如果您对 Boost 库有所了解,那么您可能想阅读 Boost.Bimap,这就是您在此处实施的内容。

http://www.boost.org/doc/libs/1_42_0/libs/bimap/doc/html/index.html

http://www.boost.org/doc/libs/1_42_0/libs/bimap/doc/html/index.html

回答by Puppy

Static is bad. Don't. Also, throw or return NULL pointer on not found, not return empty string. Other_func should be a member method on the object of Mapping, not a static method. This whole thing desperately needs to be an object.

静电不好。别。此外,在未找到时抛出或返回 NULL 指针,不返回空字符串。other_func 应该是 Mapping 对象上的成员方法,而不是静态方法。这整个事情迫切需要成为一个对象。

template<typename Key, typename Value> class Mapping {
    std::map<Key, Value> primmap;
    std::map<Value, Key> secmap;
public:
    template<typename Functor> Mapping(Functor f) {
        f(primmap);
        struct helper {
            std::map<Value, Key>* secmapptr;
            void operator()(std::pair<Key, Value>& ref) {
                (*secmapptr)[ref.second] = ref.first;
            }
        };
        helper helpme;
        helpme.secmapptr = &secmap;
        std::for_each(primmap.begin(), primmap.end(), helpme);
    }
    Key& GetKeyFromValue(const Value& v) {
        std::map<Value,Key>::iterator key = secmap.find(v);
        if (key == secmap.end())
            throw std::runtime_error("Value not found!");
        return key->second;
    }
    Value& GetValueFromKey(const Key& k) {
        std::map<Key, Value>::iterator key = primmap.find(v);
        if (key == primmap.end())
            throw std::runtime_error("Key not found!");
        return key->second;
    }
    // Add const appropriately.
};

This code uses a function object to initialize the map, reverses it for you, then provides accessing methods for the contents. As for why you would use such a thing as opposed to a raw pair of std::maps, I don't know.

这段代码使用一个函数对象来初始化地图,为你反转它,然后提供内容的访问方法。至于为什么你会使用这样的东西而不是一对原始的 std::maps,我不知道。

Looking at some of the code you've written, I'm guessing that you originate from Java. Java has a lot of things that C++ users don't use (unless they don't know the language) like singletons, statics, and such.

看看你写的一些代码,我猜你来自 Java。Java 有很多 C++ 用户不使用的东西(除非他们不知道该语言),比如单例、静态等等。