我正在尝试自学 C++(实际上我应该说重新学习,但我第一次学习它是在一年前我对编码一窍不通的时候所以它不算数)而且我正在做我完成在线教程后的第一个项目。我想既然我有很好的 C# 和 VB.Net 背景,我不妨尝试一些更大的东西,但不要太大。在开始之前,我使用 Code::Blocks 作为我的 IDE 和该 IDE 中的默认编译器(我相信它是 MinGW)。所以这是我的事情:我有一个 ChromaTest 项目(对于那些想知道名称的人,这是使用 Razer Chroma SDK),它是一个控制台应用程序,还有一个 ChromaTestDLL 项目,它是(你猜对了)一个 DLL(我决定做一个 DLL 来学习如何同时这样做,因为我稍后可能会在 GUI 项目中使用一些代码)。问题是我在尝试插入 map 时遇到段错误。这是相关代码:
在 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类的Header,与ChromaTestDll中的略有不同,基本上只包含public成员)
#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;
}
抱歉,代码太长了(请告诉我是否可以删除此处的内容)。任何人都可以发现其中的任何错误我不会感到惊讶这将链接到指针,这可能是我花了最多时间来理解的概念。起初我没有将 map 放在指针和堆上,但将另一个变量更改为之前的变量似乎解决了另一个问题,所以我想我会试一试。遗憾的是,当我没有将 map 也放在堆上时,我也遇到了几乎相同的错误。
附带说明一下,谁能向我解释一下堆和堆栈之间的区别,为什么我要经历在堆上存储变量(有指针和删除等等)的(有风险的)麻烦,而不是在堆栈上,什么时候应该使用堆,什么时候不应该。
最佳答案
根据您问题中的信息:
DLL 中的已编译代码似乎在其头文件中声明了一个包含一堆内部类成员的
MyChroma
类。然后您的主应用程序使用一个完全不同的头文件,它定义了一个名为
MyChroma
的类,剥离了它的类成员。然后,您的主应用程序根据它在头文件中看到的内容实例化
MyChroma
类。
那是行不通的。由于您的主应用程序对这些类成员一无所知,因此它实例化的实际类太小了。
然后它在堆栈上实例化一个类。
然后构造函数来自 DLL,它认为该类包含所有其他类成员。
并且 DLL 中的构造函数尝试初始化它们。
在堆栈上。
你好堆栈损坏。
这里的答案很简单“不要做你做过的事”。这是未定义的行为。您编译的所有引用特定类的内容都必须看到该类的相同声明(和内联方法定义)。
句号。
没有异常(exception)。
好吧,如果有足够的经验,当针对特定的 C++ 实现时,可以安全地执行类似的操作,但这里不是这种情况。
在那之前,有很多方法可以隐藏库提供的类的内部实现细节,但这不是您的做法。安全的方法是使用 PIMPL design pattern .
还有一些您不应该做的事情。这与手头的问题没有直接关系,但这将避免其他几个常见的陷阱,这些陷阱可能会在没有事先警告的情况下将地毯从你的脚下拉下来:
不要使用 use namespace std; .特别是在头文件中。完全忘记 C++ 语言中存在类似的东西。
你所有的类(class)也应该follow the Rule Of Three .
关于std::map::insert 处的 C++ 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39432020/