C++ C++;映射将向量下标抛出范围之外

C++ C++;映射将向量下标抛出范围之外,c++,stl,unordered-map,C++,Stl,Unordered Map,我正在尝试创建一个类,该类将其实例存储在映射中,如下所示: 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

我正在尝试创建一个类,该类将其实例存储在映射中,如下所示:

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 });
        }
}

当我运行该程序时,它在getApple()方法的第一行崩溃,并出现向量下标超出范围的错误。我试着四处看看,但我真的找不到任何解决方案来处理地图和这个超出范围的错误。根据我所做的一些研究,我的猜测是关于静态顺序初始化的,但我真的不太确定。

首先,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");
苹果类{ 公众: 静态Apple*getApple(const std::string和name){ auto it=allApples.find(名称); if(it==allApples.end())//如果这个苹果不存在,就做一个新的 返回新苹果(名称); else//如果苹果存在,则返回其指针 返回->秒; } 私人: 静态std::无序映射所有应用程序; 苹果(const std::string和name){ //创造一个苹果 插入({name,this}); } }; std::无序映射Apple::allApples=std::无序映射(); 橙色类{ 静态苹果*myorange苹果; }; 苹果*Orange::myOrangeApple=Apple::getApple(“橙色”);
在初始化之前,您正在访问所有应用程序。在您输入
main
之前,无法保证
allApples
已构建,因此访问它是绝对不允许的


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

使用函数范围静态对象

...
private:
   std::unordered_map<std::string, Apple*>& allApples() {
      static std::unordered_map<std::string, Apple*> apples;
      return apples;
   }
。。。
私人:
标准::无序地图和所有地图(){
静态标准::无序的_图苹果;
还苹果;
}
这是对抗静态初始化命令失败的标准方法之一。它之所以有效,是因为块作用域静态对象保证在第一次执行块时初始化


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

你指的第一行是
autoit=allApples.find(name)?我看不到任何与
std::vector
或下标运算符相关的内容。@songyuanyao,是的,该行是抛出调试断言/异常(在发布版本中)的行。我也看不到任何与向量相关的东西,这就是为什么我如此困惑的原因。你能给我们足够的代码,让我们可以编译它并复制这个问题吗?@DavidSchwartz,这就是它的全部。。。除了一个函数和构造函数之外,我没有访问
allApples
映射,因此编写
main
函数并确认它复制了问题应该没有问题。请这样做。我有这样的代码,我可能应该在这里更改它,我只是不认为它与问题有那么大的关系。@ThomasPaine没有足够的代码来复制问题,任何人都无法判断什么是相关的或不相关的。但是当我在断点之前打印出
allApples
的大小时,它给我零,这意味着
allApples
已初始化,对吗?如果
allApples
没有初始化,那不是未定义的行为吗?@thomaspine这是代码中的另一个bug。在确保所有应用程序都已初始化为UB之前,不得调用
size
。你刚好得到零,这误导了你。这就是为什么你不应该这么做!这就是为什么您应该在构造函数和析构函数中尽可能少地执行操作——很难控制它们执行的上下文。让这么多的代码都从全局静态的构造函数调用是愚蠢的。您如何维护这段代码,而不在代码上到处贴上“请勿在MAIN之前执行任何不合法的操作”的大警告,并通过所有调用的函数传播这些警告?疯了,在这种情况下我该怎么办?构建苹果非常昂贵(这是一个文件导入和处理过程),因此我不想每次需要访问苹果时都构建它们。您可以使用一个工厂类来管理苹果。这是一个很好的建议,但作为一个答案,如果您解释为什么这样做会更好,那会更好。
...
private:
   std::unordered_map<std::string, Apple*>& allApples() {
      static std::unordered_map<std::string, Apple*> apples;
      return apples;
   }