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

Access violation when inserting element into global map

本文关键字:访问冲突 元素 插入 全局 映射      更新时间:2023-10-16

我已经试着调试了好几个小时了,但没有成功。我知道你们会在几分钟内解决问题,所以情况如下:

我有大约400.cpp/.h文件,名为ProbemX.cpp/ProbemX.h(其中X是从1到400的数字)。每个文件都包含一个数学相关问题的解决方案。我想让这些问题在编译时用一个唯一的键(只需要一个int就可以了)将自己注册到一个全局映射中,并将该值作为启动数学问题解决方案的函数的指针。

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

在ProblemX.h文件中(problem1启动了该问题的解决方案):

#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.pp:

#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;"处。

谢谢!

正如神秘命名的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变量初始化后(在您的情况下肯定是这样)。

小心使用这样的静态它们的定义顺序可能会有所不同。变量可能存在,但不一定是构造的。这件事昨天真的咬了我一口,所以我记忆犹新。

Problems.cpp中,事物的定义顺序为:

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

这意味着rc1problems_map之前被初始化。

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

我一直以为编译器会解决这个问题。但仔细想想,一般情况很难考虑(尤其是当你最终产生相互依赖关系时)。因此,我认为唯一明智的做法是期望程序员按照正确的顺序放置静态定义,就像他们应该对任何其他代码语句所做的那样。

查看构造函数上的C++常见问题解答。特别检查问题10.14至10.18-"静态初始化顺序失败"。

什么是"静态初始化顺序惨败"?

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

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

简而言之,假设您有两个静态对象x和y,它们存在于单独的源文件,比如x.cpp和y.cppy对象的初始化(通常是y对象的构造函数)调用x对象上的某个方法。

就这样,就这么简单。