我正在尝试自学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;
}
很抱歉这个代号很长(请告诉我是否有我可以删除的内容)。任何人都可以发现任何错误,我不会感到惊讶,这将与指针相关联,这可能是我花费最多时间理解的概念。起初我没有将地图放在指针和堆上,但是将另一个变量更改为先前的变量似乎修复了另一个问题,所以我想我试一试。可悲的是,当我没有将地图放在堆上时,我也有同样的错误。
另一方面,任何人都可以向我解释堆和堆栈之间有什么不同,为什么我要经历(存在风险)将变量存储在堆上的麻烦(使用指针和删除以及所有)而不是在堆栈上,什么时候应该使用堆,或者什么时候不应该使用堆。
答案 0 :(得分:2)
根据您问题中的信息:
DLL中的已编译代码似乎在其头文件中声明了一个包含一堆内部类成员的MyChroma
类。
然后你的主应用程序使用一个完全不同的头文件,它定义了一个名为MyChroma
的类,剥离了它的类成员。
然后,您的主应用程序根据它在头文件中看到的内容实例化MyChroma
类。
那不行。由于您的主应用程序对这些类成员一无所知,因此它实例化的实际类太小了。
它在堆栈上实例化一个类。
然后构造函数来自DLL,它认为该类包含所有其他类成员。
DLL中的构造函数尝试初始化它们。
在堆栈上。
Hello堆栈损坏。
这里的答案就是“不要做你做的事”。这是未定义的行为。您编译的所有引用特定类的内容都必须看到该类的相同声明(和内联方法定义)。
完全停止。
没有例外。
嗯,有了足够的经验,在针对特定的C ++实现时,可以安全地做这样的事情,但这不是这里的情况。
在此之前,有一些方法可以隐藏库提供的类的内部实现细节,但这不是你如何做到的。安全的方法是使用PIMPL design pattern。
其他一些你不应该做的事情。这与手头的问题没有直接关系,但这可以避免其他几个常见的陷阱,如果没有提前警告,可以从脚下拉出地毯:
请勿使用use namespace std;。特别是在头文件中。完全忘记C ++语言中存在类似的东西。
您的所有课程也应follow the Rule Of Three。