2016-09-11 3 views
0

Я пытаюсь научить себя C++ (на самом деле я должен повторить обучение, но я впервые узнал об этом, когда я ничего не знал о кодировании и год назад, так что это не считается), и я делаю свой первый проект после окончания онлайн-урока. Я подумал, что, поскольку у меня были хорошие C# и VB.Net-фон, я мог бы попробовать нечто большее, но не слишком большое. Прежде чем начать, я использую Code :: Blocks в качестве моей IDE и компиляторе по умолчанию в этой среде IDE (я считаю, что это MinGW). Итак, вот что я делаю: у меня есть проект ChromaTest (это использует Razer Chroma SDK для тех, кто задается вопросом об имени), который представляет собой консольное приложение, и проект ChromaTestDLL, который (вы уже догадались) DLL (я решил сделать DLL, чтобы узнать, как это сделать в одно и то же время, и потому, что позже я смогу использовать код в проекте GUI). Проблема в том, что я получаю ошибку с ошибкой сегментации при попытке вставить в карту. Вот соответствующий код:C++ Ошибка сегментации на std :: map :: insert

В ChromaTestDLL проекта

MyChroma.h (Header для класса 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 (Header импортировать класс 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; 
} 

Извините за ужасно длинный код (скажите, пожалуйста, если есть тонкие gs я мог бы удалить здесь). Может ли кто-нибудь обнаружить какую-либо ошибку там, я бы не удивился, что это будет связано с указателями, это, вероятно, концепция, которая заняла у меня больше времени, чтобы понять. Сначала я не помещал карту в указатель и кучу, но изменение другой переменной на прежнюю, похоже, устранило еще одну проблему, поэтому я решил, что попробую. К сожалению, у меня были почти такие же ошибки, когда я не клал карту на кучу.

На стороне примечания, может ли кто-нибудь объяснить мне, что отличается между кучей и стеком, почему бы мне хотеть пройти через (рискованную) проблему хранения переменных в куче (с указателями и удалением и все) вместо этого в стеке, и когда я должен использовать кучу, или когда мне это не нужно.

+4

Хорошие новости! Сегодня, на stackoverflow.com, мы запускаем рекламную кампанию под названием «Ответ на свой вопросный день». Мы тайно разместили на вашем компьютере очень продвинутый инструмент, называемый «отладчиком». Используя этот замечательный инструмент, вы можете выполнять свою программу по одной строке за раз, анализировать все значения всех переменных и «отлаживать» свой код, тем самым отвечая на свой собственный вопрос. Не пропустите эту увлекательную возможность ответить на свой вопрос, только сегодня, на stackoverflow.com! –

+2

Вы нарушили Правило Трех, и теперь оно вернулось, чтобы сломать вас. –

+0

Почему бы вам не объявить свою 'std :: map' в качестве указателя ?? Не событие уникальное ... –

ответ

2

Основываясь на информации в вашем вопросе:

  1. Составленный код в вашей DLL появляется объявить MyChroma класс, содержащий кучу внутренних членов класса, в заголовочном файле.

  2. Тогда ваше основное приложение использует совершенно другой файл заголовка, который определяет класс MyChroma, лишенный его членов класса.

  3. Затем ваше основное приложение создает класс MyChroma, основываясь на том, что он видит в своих заголовочных файлах.

Это не сработает. Поскольку ваше основное приложение ничего не знает об этих членах класса, фактический класс, который он создает, слишком мал.

И он создает экземпляр класса в стеке.

И затем конструктор приходит из библиотеки DLL, которая считает, что класс содержит все остальные члены класса.

И конструктор в DLL пытается их инициализировать.

В стеке.

Привет, стека коррупции.

Ответ здесь просто «не делай, что ты сделал». Это неопределенное поведение. Все, что вы компилируете, ссылаясь на определенный класс, должно видеть идентичное объявление (и встроенные определения метода) этого класса.

Полная остановка.

Исключение составляют исключения.

Ну, с достаточным опытом, можно сделать что-то подобное безопасно, когда вы нацеливаете конкретную реализацию на C++, но здесь это не так.

До тех пор существуют способы скрыть внутренние детали реализации классов, предоставляемых библиотекой, но это не то, как вы это делаете. Безопасный способ сделать это с PIMPL design pattern.

Несколько других вещей, которые вы не должны делать, также. Это не относится непосредственно к проблеме под рукой, но это позволит избежать ряда других распространенных ошибок, которые могут, без предварительного предупреждения, тянуть ковер из-под ног:

  1. Не используйте use namespace std;. Особенно в заголовочных файлах. Полностью забыть, что что-то подобное существует на языке C++.

  2. Все ваши классы также должны быть follow the Rule Of Three.

+0

Спасибо за указание на недостатки в моем дизайне/реализации.Я посмотрю, что вы указали на связь и переделаете проект с самого начала. –