将元素插入全局映射时发生访问冲突

时间:2012-11-12 23:47:29

标签: c++ map

我一直在努力调试这几个小时而没有运气。我知道你们会在几分钟内解决问题,所以情况如下:

我有~400个.cpp / .h文件,名为ProblemX.cpp / ProblemX.h(其中X是1到400之间的数字)。每个文件都包含与数学相关的问题的解决方案。我想让问题在编译时自己注册到具有唯一键的全局映射(只有一个int可以工作),并且值是指向启动数学问题解决方案的函数的指针。

在名为Problem.h / Problem.cpp的文件中创建和处理全局映射。但是,当第一个问题试图在地图中自行注册时,我收到“访问冲突读取位置0x00000004”。代码如下:

在ProblemX.h文件中(问题1启动了解决此问题的方法):

#ifndef PROBLEM1_H
#define PROBLEM1_H

#include "Problems.h"
#include <string>

std::string problem1();
static int rc1 = registerProblem(1, problem1);

#endif

在Problems.h文件中(problemFinder是使用全局映射调用相应函数指针的函数):

#ifndef PROBLEMS_H
#define PROBLEMS_H

#include <string>

int registerProblem(int problemNum, std::string (*problemFunc)(void));
std::string problemFinder(int problemNum);

#endif

在Problems.cpp中:

#include "Problems.h"
#include <iostream>
#include <map>

using namespace std;

map<int,std::string (*)(void)> problems_map;

int registerProblem(int problemNum, string (*problemFunc)(void)) {
    int rc = 0;
    problems_map[problemNum] = problemFunc;
    return rc;
}


string problemFinder(int problemNum) {
    string retStr = "";
    retStr = problems_map[problemNum]();
    return retStr;
}

访问冲突发生在“problems_map [problemNum] = problemFunc;”。

的位置

谢谢!

3 个答案:

答案 0 :(得分:4)

由于神奇地命名为user93353,因此不保证在其他文件中的全局变量之前构造problems_map全局。

要避免静态初始化顺序失败,请使problems_map成为本地静态,这将在首次使用时初始化:

map<int,std::string (*)(void)>&
get_problems_map()
{
  static map<int,std::string (*)(void)> problems_map;
  return problems_map;
}

然后像这样使用它:

get_problems_map()[problemNum] = problemFunc;

这确保了地图在需要时立即创建,而不仅仅是来自Problems.cpp的全局构造函数运行时,这可能是(并且在您的情况下肯定是)全局rc1变量之后得到初始化。

答案 1 :(得分:3)

请注意使用这样的静态。定义它们的顺序可能会有所不同。变量可能存在,但不一定构造。这实际上是我昨天的屁股,所以它记忆犹新。

Problems.cpp中,订单的定义是:

static int rc1 = registerProblem(1, problem1);
map<int,std::string (*)(void)> problems_map;

这意味着在rc1之前初始化problems_map

因此,您的问题就出现了,因为调用registerProblem初始化rc1并使用尚未构建的problems_map

我一直以为编译器会解决这个问题。但是当你考虑它时,一般情况下很难考虑(特别是如果你最终会有相互依赖)。所以我想唯一明智的做法是期望程序员以正确的顺序放置他们的静态定义,就像他们应该对任何其他代码语句一样。

答案 2 :(得分:1)

查看Constructors上的C ++常见问题解答。特别是检查问题10.14到10.18 - “静态初始化命令惨败”。

  

什么是“静态初始化命令惨败”?

     

使程序崩溃的一种微妙方法。

     

静态初始化顺序fiasco是一个非常微妙和常见的   误解了C ++的一个方面。不幸的是,它很难被发现 -   错误经常发生在main()开始之前。

     

简而言之,假设你有两个静态对象x和y   单独的源文件,比如x.cpp和y.cpp。进一步假设   y对象的初始化(通常是y对象的构造函数)   在x对象上调用一些方法。

     

就是这样。就这么简单。