Как избежать утечки памяти при инициализации карты в конструкторе класса? - PullRequest
4 голосов
/ 11 мая 2019

Я хотел бы инициализировать (указатель на) map в конструкторе класса.Программа, которую я написал, компилируется, но не выполняется во время выполнения из-за ошибки сегментации.Я могу решить проблему путем динамического выделения памяти для map, но Valgrind сообщает мне об утечке памяти.Как правильно инициализировать класс?

Вот пример

#include <iostream>
#include <map>
#include <string>
#include <vector>

class MemoryLeak {
   public:
    MemoryLeak(std::vector<std::string>& inp) {
        int i = 0;
        std::map<std::string, int>* tmp = new std::map<std::string, int>;
        for (std::string& s : inp) {
            //(*problem_map)[s] = i++; // Line 12: causes a seg fault
            (*tmp)[s] = i++;
        }
        problem_map = tmp;  // Line 15: memory leak
    }
    std::map<std::string, int>* problem_map;
};

int main() {
    std::vector<std::string> input{"a", "b"};
    MemoryLeak mem = MemoryLeak(input);
    for (auto const& it : *(mem.problem_map)) {
        std::cout << it.first << ": " << it.second << "\n";
    }
    return 0;
}

Когда я раскомментирую line 12 (и закомментирую Line 15), программа компилируется, но возникает утечка памятипроисходить.Может кто-нибудь любезно сказать мне, что я делаю не так?Как будет выглядеть более подходящий конструктор?

1 Ответ

2 голосов
/ 11 мая 2019

Для segfault :

Ваш указатель problem_map неинициализирован в строке 12. Именно поэтому segfault.Вам не нужно tmp, вы можете просто сделать это:

problem_map = new std::map<std::string, int>;
for (std::string& s : inp) {
    (*problem_map)[s] = i++; 
}

Теперь для утечки у вас есть два варианта:

1) Добавить деструктор, конструктор копированияи оператор копирования-присвоения (или сделать их удаленными).См. Правило три

class MemoryLeak {
   public:
    ~MemoryLeak() {
        delete problem_map;
    }
    MemoryLeak(const MemoryLeak& ) = delete;
    MemoryLeak& operator=(const MemoryLeak& ) = delete;
    MemoryLeak(std::vector<std::string>& inp) {
        int i = 0;
        problem_map = new std::map<std::string, int>;
        for (std::string& s : inp) {
           (*problem_map)[s] = i++; 
        }
    }
    std::map<std::string, int>* problem_map;
};

2) не хранить указатель, а карту

class MemoryLeak {
   public:
    MemoryLeak(std::vector<std::string>& inp) {
        int i = 0;
        for (std::string& s : inp) {
            problem_map[s] = i++;
        }
    }
    std::map<std::string, int> problem_map;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...