2017-01-19 9 views
1

Я решил изменить свой код сегодня от vector до unordered_map, поэтому у меня могут быть значения строковых ключей. Однако, похоже, что unordered_map не совсем работает.C++ - проблемы с памятью unordered_map со структурой

Так в основном у меня есть тип структуры:

typedef struct WindowData //the infamous Window Data struct 
{ 
    HWND handle; 
    std::unordered_map<std::string, WindowData*> children; 
    COLORREF color; 
    int height; 
    int width; 
    int x; 
    int y; 
    WindowData *parent; 
    bool visible; 
} windowData; 

, а затем глобально определенный экземпляр этого:

WindowData MainWData = {NULL, std::unordered_map<std::string, WindowData*>(), NULL, 0, 0, 0, 0, NULL, true}; 

Тогда функция добавляет элемент к unordered_list (STRUCT член children) :

void GUI::CreateTitle(WindowData *data) //Home/About page title 
{ 
    /*...*/ 
    WindowData wd={handle, std::unordered_map<std::string, WindowData*>(), ColorPalette.BackgroundColor, Nheight, Nwidth, x, y, data, true}; //all these values are defined within the scope of this function except ColorPalette, which is global 
    data->children.insert(std::make_pair("title", &wd)); 
} 

Наконец, у меня есть еще несколько функций, i зажимные как членов и нечленов класса GUI, которые считывают элемент карты, такие как этот:

void GUI::CreateAboutButton(WindowData *data) //Home Page About Button 
{ 
    /*...*/ 
    int y=data->children.at("title")->y + data->children.at("title")->height + 100; 
    /*...*/ 
} 

Теперь, чтобы описать эту ошибку. Возьмите int y с функции GUI::CreateAboutButton(). При каждом запуске программы значение должно быть одинаковым. Обычно это что-то вроде 219. Однако теперь он меняется при каждом запуске программы. Иногда y - правильное значение. Другие времена это 0. В других случаях это больше, чем 40 000.

Я знаю, что это проблема с памятью, потому что иногда, когда программа запускается, она немедленно сигнализирует о segfault, а когда это не так, Dr. Память показывает две дюжины ошибок «Uninitialized Read». Я предполагаю, что поскольку значение unordered_map должно быть указателем на структуру (программа не будет компилировать, если это просто значение структуры, а не указатель), как только экземпляр структуры wd из GUI::CreateTitle() выходит за пределы области действия, карта по-прежнему указывает на прежнее место памяти вместо фактического экземпляра. Но то, что я не знаю, как это сделать (это моя первая реализация unordered_map), - это проблема. Я попытался отключить unordered_map::insert для unordered_map::emplace, но это привело к последовательному segfault.

Любая помощь приветствуется.

EDIT: диагнозы/решения в комментариях ниже приводят меня к решению проблемы путем определения wd в качестве публичного участника класса. Теперь он отлично работает, и все ошибки памяти устранены.

+3

'& wd' дает вам указатель на локальные данные в' CreateTitle'. Когда функция возвращается, она удаляется. Вам нужно будет создать его в другом месте, например. с 'new' (хотя я не рекомендую его), или перестать использовать необработанные указатели и наблюдать всевозможные проблемы, просто волшебным образом уйти. – Biffen

+1

'* Это мой первый раз, когда вы выполняете unordered_map * «Вы не реализуете, вы просто используете. – Biffen

+2

Создайте свои объекты в куче. – MikeMB

ответ

3

Проблема заключается в сохранении указателя на локальную переменную wd на карте. Локальная переменная уничтожается в конце CreateTitle, и указатель на карте становится свисающим. Одним из возможных решений для карты иметь детей WindowData, например с помощью unique_ptr:

std::unordered_map<std::string, std::unique_ptr<WindowData>> children; 

А затем создать его на месте:

void GUI::CreateTitle(WindowData *data) 
{ 
    /*...*/ 
    data->children.emplace(
     "title", 
     make_unique<WindowData>(handle, std::unordered_map<std::string, std::unique_ptr<WindowData>>(), ColorPalette.BackgroundColor, Nheight, Nwidth, x, y, data, true) 
    ); 
} 

Добавить EDIT: Определение wd как общественный член WindowData работает только в том случае, если есть только один ребенок. Однако тогда не было бы смысла иметь карту, не так ли?

+0

Вы правы; мое решение 2AM не то, что я пытаюсь сделать здесь. Я хотел бы принять это решение здесь, за исключением того, что мой компилятор устарел, поэтому я ограничен функциями C++ 11. – Homberto

+0

@Homberto: Достаточно просто избавиться от 'make_unique', но сделать переменную' std :: unique_ptr wd (new /*...*/) 'и' std :: переместить ее на карту в 'emplace'. –