Я работаю с C ++ и использую valgrind для устранения утечек памяти.
Я пытаюсь оптимизировать следующий фрагмент кода, который valgrind характеризует как утечку:
void VOMC::sub_train(vector<Letter> tempLettersA, vector<Letter> tempLettersB) {
int stateA_id = state_exists(tempLettersA);
State *tempStateA;
if (stateA_id != -1) {
tempStateA = get_state_by_id(stateA_id);
} else {
tempStateA = new State(tempLettersA);// MEMORY LEAK - 1
vomc.push_back(tempStateA);
}
int stateB_id = state_exists(tempLettersB);
if (stateB_id != -1) {
tempStateA->inc_state(stateB_id);
} else {
State* tempStateB;
tempStateB = new State(tempLettersB);//MEMORY LEAK -2
vomc.push_back(tempStateB);
stateB_id = tempStateB->GetId();
tempStateA->inc_state(stateB_id);
}
}
Для утечки памяти-1 я получаю следующее сообщение
==11289== 4,055 (64 direct, 3,991 indirect) bytes in 1 blocks are definitely lost in loss record 228 of 228
==11289== at 0x402B87E: operator new(unsigned int) (vg_replace_malloc.c:292)
==11289== by 0x807FA75: VOMC::sub_train(std::vector<Letter, std::allocator<Letter> >, std::vector<Letter, std::allocator<Letter> >) (VOMC.cpp:952)
Для утечки памяти -2
==11289== at 0x402B87E: operator new(unsigned int) (vg_replace_malloc.c:292)
==11289== by 0x807FB16: VOMC::sub_train(std::vector<Letter, std::allocator<Letter> >, std::vector<Letter, std::allocator<Letter> >) (VOMC.cpp:968)
Могу ли я удалить эти указатели? Это устранит мои утечки, НО, поскольку вы можете видеть, как указатели помещаются в стек, цель состоит в том, чтобы сохранить их в стеке, но устранить утечку.
РЕДАКТИРОВАТЬ -1: добавление буквы и определения штата:
class Letter {
public:
Letter();
Letter(Helper *helper);
~Letter();
void add_note(RawNote r);
void evaluate_letter(double eigthNoteDuration);
void setNotePositionAccordingToLetter();
void empty_notes();
LetterPattern getPattern() const;
void setPattern(LetterPattern pattern);
bool isEmpty();
vector<RawNote> getRawNotes() const;
void setRawNotes(vector<RawNote> rawNotes);
bool has_note_no_velocity(RawNote* r1);
bool has_note_with_velocity(RawNote* r1);
private:
vector<LetterPattern> *allPossibleNotes;
vector<RawNote> rawNotes;
LetterPattern pattern;
};
class State {
public:
State(); //should not be used, it is only for testing
State(vector<Letter> letters);
virtual ~State();
int GetId() const;
void SetId(int id);
vector<Letter> GetLetters() const;
void SetLetters(vector<Letter> letters);
void AddLetters(vector<Letter> letters);
void inc_state(int state_id);
void print_state_letters();
bool has_state(int state_id);
void print_connected_states();
void print_sorted_states();
vector<string> get_rhythm_as_string();
map<int, double> GetConnected_states() const;
map<int, double> connected_states;
vector< pair <int, double > > vector_sorted_connected_states;
void bubblesort_vector_descending(vector< pair <int, double > > *v_sort);
int get_connected_state_stochastically();
static int id_generator;
CustomNumberDist *normal_dist;
int id_from_file; //only used on load of a file
private:
int id;
vector<Letter> letters;
};
Все, что Valgrind может сказать вам, является источником утечки. Он не может сказать вам, где отсутствующий вызов delete
это … это не хватает.
Одним из решений является удаление указателей после выталкивания их из стека и получения VOMC::~VOMC()
удалить все элементы, которые остаются в стеке. Этот подход работает, только если класс VOMC
«владеет» каждым из объектов в стеке. Этот подход не может работать, если стек также содержит указатели на State
объекты, которые так или иначе принадлежат другому объекту.
Работа со смешанным владением немного сложнее с контейнерами необработанных указателей. Один из способов справиться с контейнером сырых указателей, в которых смешано владение, — это добавить owned_by
указатель на класс State
(или что бы то ни было содержится). Теперь твой класс VOMC
удаляет только те объекты, которые принадлежат this
, Здесь есть архитектурная проблема: она пахнет запахом кода. Аналог этого подхода существует в SWIG, где вам иногда нужно установить thisown
свойство ложно. Мой датчик запаха кода зашкаливает, когда я вижу подобные вещи.
Третий подход — просто избавиться от этих сырых указателей. Вместо набора сырых указателей сделайте свой vomc
элемент данных коллекция объектов (не указателей), которые являются экземплярами какого-либо интеллектуального указателя. Это современный подход к работе с необработанными указателями, который заключается не в использовании необработанных указателей.
Других решений пока нет …