【问题标题】:C++ - Initializing a static map as a private class memberC++ - 将静态映射初始化为私有类成员
【发布时间】:2011-06-02 19:30:06
【问题描述】:

假设我在一个深夜很无聊,在紧张地盯着电脑显示器几个小时之后,我决定实现一个聚合 C++ 类来管理绘制像素的颜色,因为我显然已经疯了。对于初学者,我们只需告诉(可能是单例的)ColorManager 对象我们想要使用什么颜色,然后它会返回一个 Color 对象,无论它是什么。

一个简单的实现:

#include "Color.h"
#include <map>

enum COLOR { RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK,
    BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON,
    // etc
    COLOR_COUNT };

class ColorManager
{
public:
    ColorManager();
    ~ColorManager();
    Color getColor(COLOR color) const;
private:
    typedef std::map<COLOR, Color> ColorMap;
    static ColorMap colorMap;
};

所以,希望这个简单的代码:

ColorManger colorManager;
Color blue = colorManager.getColor(BLUE);

应该让我们很容易做任何你需要Color对象的废话。

问题是您需要在某处初始化您的静态私有ColorMap,以便每个COLOR 枚举对应于正确的Color 对象,而VC++ 2010 似乎不喜欢您尝试的任何东西。所以问题是,我如何以及在哪里初始化这个地图?

显然,这是一个人为的例子,但除此之外,为一个作为单例运行的类定义静态变量可能不值得麻烦。或者,也许,我还不如在 getColor() 中声明变量 static ,因为这是唯一使用它的函数,并且在第一次调用该函数时会产生开销(尽管对于这个简单的示例,这并没有好多少)不仅仅是在其中放置一个巨大的 switch 语句)。

无论如何,我感谢您的反馈。

【问题讨论】:

    标签: c++ dictionary static stl


    【解决方案1】:
    #include <map>
    #include "Color.h"
    
    enum COLOR
    {
        RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK,
        BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON,
        // etc
        COLOR_COUNT
    };
    
    class ColorManager
    {
        typedef std::map<COLOR, Color> ColorMap;
    
    public:
        ColorManager();
        Color getColor(COLOR color) const;
    
    private:
        static ColorMap createColorMap();
        static ColorMap colorMap;
    };
    
    // in some .cpp file:
    
    ColorManager::ColorMap ColorManager::createColorMap()
    {
        ColorMap ret;
        // populate ret
        return ret;
    }
    
    ColorManager::ColorMap ColorManager::colorMap = ColorManager::createColorMap();
    

    或使用 C++11:

    #include <map>
    #include "Color.h"
    
    enum COLOR
    {
        RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK,
        BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON,
        // etc
        COLOR_COUNT
    };
    
    class ColorManager
    {
        using ColorMap = std::map<COLOR, Color>;
    
    public:
        ColorManager();
        Color getColor(COLOR color) const;
    
    private:
        static ColorMap colorMap;
    };
    
    // in some .cpp file:
    
    ColorManager::ColorMap ColorManager::colorMap = []
    {
        ColorMap ret;
        // populate ret
        return ret;
    }();
    

    【讨论】:

      【解决方案2】:

      std::map 有一个构造函数,它接受一对迭代器作为参数,因此您可以使用例如一对数组来初始化映射:

      #include "Color.h"
      
      #include <map>
      
      enum COLOR { RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK,
          BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON,
          // etc
          COLOR_COUNT };
      
      class ColorManager
      {
      public:
          ColorManager();
          ~ColorManager();
          Color getColor(COLOR color) const;
      private:
          typedef std::map<COLOR, Color> ColorMap;
          static ColorMap colorMap;
      };
      
      using std::make_pair;
      using std::pair;
      
      std::pair<COLOR, Color> colorPairs[] = {make_pair(RED, Color(...)),
                                              make_pair(BLUE, Color(...)),
                                              make_pair(GREEN, Color(...)),
                                              ...};
      
      ColorManager::ColorMap ColorManager::colorMap(colorPairs, colorPairs + COLOR_COUNT);
      

      在 C++0x 中,您将能够简单地执行此操作:

      ColorManager::ColorMap ColorManager::colorMap({{RED, Color(...)},
                                                     {BLUE, Color(...)},
                                                     {GREEN, Color(...)},
                                                     ...});
      

      【讨论】:

        【解决方案3】:

        使用创建初始化地图的静态方法:

        ColorManager::colorMap(ColorManager::makeColorMap());
        

        其中makeColorMap 是以下静态方法:

        ColorManager::ColorMap ColorManager::makeColorMap()
        {
          ColorMap retval;
          retval[...] = ...;
          retval[...] = ...;
          ...
        
          return retval; 
        }
        

        【讨论】:

        • 我将 ildjarn 的答案标记为已接受,但这是在大约同一时间给出的相同解决方案,因此被赞成。
        • 谢谢!我注意到我们同时提交了类似的解决方案。
        【解决方案4】:

        一种选择是将ColorMaptypedef 更改为自己的自定义类型,并使用正确初始化地图内容的构造函数。这样,当您静态初始化 ColorMap 时,构造函数将使用正确的数据填充它,任何尝试使用 ColorManager 的操作都将看到正确配置的 ColorMap

        【讨论】:

          【解决方案5】:

          你可以这样做而不需要类:

          Color getColor(COLOR color)
          {
                static std::map<COLOR, Color> colorMap;
                if(colorMap.empty()) // Only runs once.
                {
                    colorMap[BLUE] = Color();
                    // ... etc ...
                }
          
                return colorMap[color];
          }
          

          【讨论】:

          • 确实,我在问题中提到了这种方法。但是,ColorManager 是一个更大、更复杂的类的模拟,具有更多的功能,所以我不想摆脱它。
          【解决方案6】:

          你在.cpp中初始化它,为

          ColorManager::ColorMap ColorManager::colorMap;
          

          ColorManager 构造函数中创建Color 的所有实例并填充它。

          【讨论】:

          • 在 VS2010 中,这会导致 xtree 中的运行时内存访问冲突,可能是在类构造函数中分配值时。但它确实可以编译。
          • @SHaun 显然你在构造函数中做错了什么......注意不要依赖其他静态变量。
          猜你喜欢
          • 1970-01-01
          • 2021-12-31
          • 1970-01-01
          • 2015-05-18
          • 1970-01-01
          • 1970-01-01
          • 2011-02-07
          • 1970-01-01
          • 2014-03-31
          相关资源
          最近更新 更多