我正在尝试自学C ++(实际上我应该说重新学习,但是在一年前我对编码一无所知时,我第一次学习了它,所以不算数),我正在做我的第一个项目完成在线教程后。我认为,由于我拥有良好的C#和VB.Net背景,因此我不妨尝试更大一点的东西,但不要太大。在开始之前,我将使用Code :: Blocks作为我的IDE和该IDE中的默认编译器(我相信它是MinGW)。所以这是我的事情:我有一个ChromaTest项目(对于想知道名称的人使用Razer Chroma SDK)是一个控制台应用程序,还有一个ChromaTestDLL项目,这是(您猜到了)一个DLL(我决定做一个DLL来学习如何同时做,因为稍后我可能会在GUI项目中使用一些代码)。问题是尝试插入地图时出现“细分错误”错误。这是相关代码:
在ChromaTestDLL项目中
MyChroma.h(MyChroma类的标题)
#ifndef MYCHROMA_H
#define MYCHROMA_H
#include <map>
#include <windef.h>
#include "RzChromaSDKTypes.h"
#include <string>
#include "Template.h"
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
using namespace std;
#ifdef __cplusplus
extern "C"
{
#endif
class DLL_EXPORT MyChroma
{
public:
MyChroma();
bool Init();
std::map<char, COLORREF> GetColorMapping();
void SetColorMapping(char key, COLORREF color);
void AssignToKeyBoard();
void SetColorFromString(string s, COLORREF color);
~MyChroma();
protected:
std::map<char, COLORREF>* _ColorMapping;
ChromaSDK::Keyboard::RZKEY KeyFromChar(char keyChar);
My_Chroma_Implementation* Chroma;
private:
};
#ifdef __cplusplus
}
#endif
#endif // MYCHROMA_H
MyChroma.cpp(MyChroma类的相关实现)
#include "MyChroma.h"
#include "Template.h"
#include <iostream>
MyChroma::MyChroma()
{
_ColorMapping = new std::map<char, COLORREF>();
}
std::map<char, COLORREF> MyChroma::GetColorMapping() { return *_ColorMapping; }
void MyChroma::SetColorMapping(char key, COLORREF color){
if (_ColorMapping->count(key) == 0)
_ColorMapping->insert(std::make_pair(key, color)); //This where the error happens
else
(*_ColorMapping)[key] = color;
}
MyChroma::~MyChroma() {
delete Chroma;
delete _ColorMapping;
}
//Other implementations omitted
在ChromaTest项目中
MyChroma.h(导入MyChroma类的标题,与ChromaTestDll中的类稍有不同,基本上只包含公共成员)
#ifndef MYCHROMA_H
#define MYCHROMA_H
#include <map>
#include <windef.h>
#include <string>
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
using namespace std;
#ifdef __cplusplus
extern "C"
{
#endif
class DLL_EXPORT MyChroma
{
public:
MyChroma();
bool Init();
std::map<char, COLORREF> GetColorMapping();
void SetColorMapping(char key, COLORREF color);
void AssignToKeyBoard();
void SetColorFromString(string s, COLORREF color);
~MyChroma();
};
#ifdef __cplusplus
}
#endif
#endif // MYCHROMA_H
Main.cpp(主应用代码)
#include <iostream>
#include "MyChroma.h"
#include <wingdi.h>
using namespace std;
int main()
{
MyChroma test = MyChroma();
bool result = test.Init();
cout << (result ? "Initialized\n" : "Failed to initialize Razer Chroma");
cout << "Setting color";
if (result){
test.SetColorMapping('a', RGB(255,0, 0)); //This call goes in the DLL where I said it failed earlier.
test.SetColorMapping('a', RGB(0,0,255));
}
return 0;
}
很抱歉这个冗长的代码(请告诉我这里是否有我可以删除的内容)。任何人都可以在那里发现任何错误,我不会对此感到惊讶,因为它将与指针相关联,这可能是使我花了最多时间来理解的概念。起初,我没有将映射放在指针和堆中,但是将另一个变量更改为较早的变量似乎已经解决了另一个问题,因此我想尝试一下。可悲的是,当我也没有将地图放到堆上时,我遇到了几乎相同的错误。
附带说明一下,有人可以向我解释一下堆和栈之间的区别是什么,为什么我要经历(危险的)麻烦,将变量存储在堆中(包括指针,删除和全部),而不是在栈上,什么时候应该使用堆,什么时候不应该使用堆。
最佳答案
根据您问题中的信息:
DLL中的已编译代码似乎在其头文件中声明了一个包含许多内部类成员的MyChroma
类。
然后,您的主应用程序使用完全不同的头文件,该头文件定义了一个名为MyChroma
的类,该类除去了其类成员。
然后,您的主应用程序根据其在其头文件中看到的内容实例化MyChroma
类。
那是行不通的。由于您的主应用程序对这些类成员一无所知,因此它实例化的实际类太小。
并实例化堆栈上的一个类。
然后,构造函数来自DLL,后者认为该类包含所有其他这些类成员。
DLL中的构造函数将尝试对其进行初始化。
在堆栈上。
你好堆栈损坏。
答案很简单,就是“不要做你所做的事情”。这是未定义的行为。您编译的引用特定类的所有内容都必须看到该类的相同声明(和内联方法定义)。
句号
没有例外。
好吧,如果有足够的经验,在针对特定的C ++实现时,可以安全地执行类似的操作,但是这里不是这种情况。
在此之前,有一些方法可以隐藏库提供的类的内部实现细节,但这不是您要做的。安全的方法是使用PIMPL design pattern。
您也不应做其他一些事情。这与手头的问题没有直接关系,但是这可以避免其他一些常见的陷阱,这些陷阱可以在没有事先警告的情况下从脚下拉地毯:
不要使用use namespace std;。特别是在头文件中。完全忘记C ++语言中存在类似的东西。
您所有的班级也应follow the Rule Of Three。
关于c++ - 在std::map::insert的C++段错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39432020/