【问题标题】:C++ Map throws vector subscript out of range [closed]C ++ Map将矢量下标抛出超出范围[关闭]
【发布时间】:2017-01-03 05:18:46
【问题描述】:

我正在尝试创建一个将其实例存储在地图中的类,如下所示:

class Apple {
    public: 
        static Apple* getApple(const std::string &name) {
             auto it = allApples.find(name);

             if (it == allApples.end()) // if this apple doesnt exist, make a new one
                 return new Apple(name); 
             else // if the apple exists, return its pointer
                 return it->second;
        }
    private:
        static std::unordered_map<std::string, Apple*> allApples =                
            std::unordered_map<std::string, Apple*>();

        Apple(const std::string &name) {
            // create an apple
            allApples.insert({ name, this });
        }
}

现在,我创建了存储静态 Apple 的类,如下所示:

class Orange {
     static Apple *myOrangeApple;
}

myOrangeApple = Apple::getApple("orange");

当我运行程序时,它在 getApple() 方法的第一行崩溃,出现向量下标超出范围错误。我试过环顾四周,但我真的找不到任何处理地图和超出范围错误的解决方案。从我所做的一些研究中,我最好的猜测是它与静态订单初始化有关,但我真的不太确定。

【问题讨论】:

  • 第一行你的意思是auto it = allApples.find(name);?我没有看到与 std::vector 或下标运算符相关的任何内容。
  • @songyuanyao,是的,那一行是抛出调试断言/异常的那一行(在发布版本中)。我也没有看到任何与矢量相关的东西,这就是我如此困惑的原因。
  • 你能给我们足够的代码以便我们编译它并复制问题吗?
  • @DavidSchwartz,这就是它的全部......除了那个函数和构造函数之外,我从来没有访问过allApples 映射
  • 那么编写main函数并确认它复制了问题应该没有问题。请这样做。

标签: c++ stl unordered-map


【解决方案1】:

使用函数范围的静态对象。

...
private:
   std::unordered_map<std::string, Apple*>& allApples() {
      static std::unordered_map<std::string, Apple*> apples;
      return apples;
   }

这是对抗静态初始化命令失败的标准方法之一。它之所以有效,是因为在第一次执行块时保证会初始化块范围的静态对象。

如果以这种方式管理的对象之间存在相互依赖关系,则此方法将不起作用。

【讨论】:

  • 这是一个很好的建议,但作为答案,如果您解释为什么会更好。
【解决方案2】:

首先你的 getApple 方法应该是静态的,你应该在类外初始化类成员(静态成员)。试试这个 -

class Apple {
    public: 
        static Apple* getApple(const std::string &name) {
             auto it = allApples.find(name);

             if (it == allApples.end()) // if this apple doesnt exist, make a new one
                 return new Apple(name); 
             else // if the apple exists, return its pointer
                 return it->second;
        }
    private:
        static std::unordered_map<std::string, Apple*> allApples; 

        Apple(const std::string &name) {
            // create an apple
            allApples.insert({ name, this });
        }
};

std::unordered_map<std::string, Apple*> Apple::allApples = std::unordered_map<std::string, Apple*>();

class Orange {
     static Apple *myOrangeApple;
};

Apple * Orange::myOrangeApple=Apple::getApple("orange");

【讨论】:

  • 我有这样的代码,我可能应该在这里更改它,我只是认为它与问题无关。
  • @ThomasPaine 没有足够的代码来复制问题,任何人都无法判断什么是相关的。
【解决方案3】:

您在allApples 初始化之前访问它。在您输入 main 之前,不能保证 allApples 已经被构造,因此访问它是绝对不允许的。

将自己添加到容器中的类是一个坏主意,但在全局对象中这样做确实很糟糕。不要那样做。

【讨论】:

  • 但是当我在断点之前打印出allApples 的大小时,它给了我零,这意味着allApples 已初始化,对吗?如果allApples没有被初始化,那不就是未定义的行为吗?
  • @ThomasPaine 这是您代码中的另一个错误。在确保将 allApples 初始化为 UB 之前,您不得调用 size。你碰巧得到零,这会误导你。这就是为什么你不应该这样做!
  • 这就是为什么你应该在构造函数和析构函数中尽可能少做——很难控制它们执行的上下文。从全局静态的构造函数中调用这么多代码真是太疯狂了。您如何维护此代码而不在其上放置大警告说“在主之前不要做任何不合法的事情”并通过所有被调用的函数传播它?疯了。
  • 在这种情况下我应该怎么做呢?构建苹果很昂贵(它是一个文件导入和处理),所以我不想每次需要访问它们时都构建它们。
  • 您可以使用管理苹果的工厂类。
猜你喜欢
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
相关资源
最近更新 更多