Способы улучшения кода C++ для полного устранения утечек памяти
Какие вещи я могу попытаться сделать с моим существующим кодом, чтобы полностью вернуть память операционной системе? Прямо сейчас в куче остается 8 байт памяти. Кроме того, я получаю эти ошибки, когда запускаю свой код через Valgrind:
#ifndef LINKEDLIST #define LINKEDLIST /** LinkedList Class Interface */ //begining update class CLinkedlist { private: struct node { node() : mData(0), mNext(nullptr) {} int mData; node* mNext; }; typedef node *nodePtr; nodePtr mHead; // As already suggested these should be local variables nodePtr mCurr; nodePtr mTemp; public: CLinkedlist() : mHead(nullptr), mCurr(nullptr), mTemp(nullptr) {} /// end of update ~CLinkedlist(); void AddNode( int); void DeleteNode( int ); void Printlist(); }; #endif /** \file Linkedlist.cpp */ /** Linkedlist Deconstructor */ CLinkedlist::~CLinkedlist(){ mCurr = mHead; mTemp = mHead; while (mCurr) { mTemp = mCurr; mCurr = mCurr->mNext; cout << mTemp->mData << " was destroyed." <<endl; delete mTemp; } mHead = nullptr; } void CLinkedlist::AddNode( int datanode){ nodePtr data = new node; data->mData = datanode; if (mHead) { /// starting from the head, walking down the list mCurr = mHead; while(mCurr->mNext != nullptr) { mCurr = mCurr->mNext; } mCurr->mNext = data; } else { mHead = data; } } void CLinkedlist:: DeleteNode(int deldata){ nodePtr delptr = nullptr; mTemp = mHead; mCurr = mHead; /// The program either walked the entire list and found /// nothing or we found our data while (mCurr != nullptr && mCurr->mData !=deldata ){ mTemp =mCurr; mCurr = mCurr->mNext; } if (!mCurr){ cout << deldata << " was not in the list\n"; delete delptr; } else { /// new code if (mHead == mCurr) mHead = nullptr; /// old code delptr = mCurr; mCurr = mCurr->mNext; mTemp ->mNext=mCurr; delete delptr; cout << "The value "<< deldata << " was deleted\n"; } } /** Displays information about our current list */ void CLinkedlist::Printlist(){ mCurr = mHead; while (mCurr) { cout << mCurr->mData << " -> " << endl; mCurr = mCurr->mNext; } } /** * \file main.cpp */ #include <cstdlib> #include "Linklist.h" using namespace std; int main (){ CLinkedlist John; John.AddNode(3); //John.DeleteNode(3); //John.AddNode(5); //John.AddNode(7); //John.Printlist(); }
Кроме того, я получаю различные ошибки на Valgrind, подобные приведенным ниже. На основе неинициализированных значений
=24530== Use of uninitialised value of size 4 ==24530== at 0x4AFB934: free_mem (in /lib/arm-linux-gnueabihf/libc-2.19.so) ==24530== by 0x4AFB3C3: __libc_freeres (in /lib/arm-linux-gnueabihf/libc-2.19.so) ==24530== by 0x4023633: _vgnU_freeres (vg_preloaded.c:61) ==24530== by 0x48C5ED7: std::ctype<char>::_M_widen_init() const (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.20) ==24530== ==24530== Conditional jump or move depends on uninitialised value(s) ==24530== at 0x4AFB9B0: free_mem (in /lib/arm-linux-gnueabihf/libc-2.19.so) ==24530== by 0x4AFB3C3: __libc_freeres (in /lib/arm-linux-gnueabihf/libc-2.19.so) ==24530== by 0x4023633: _vgnU_freeres (vg_preloaded.c:61) ==24530== by 0x48C5ED7: std::ctype<char>::_M_widen_init() const (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.20) ==24530== ==24530== ==24530== HEAP SUMMARY: ==24530== in use at exit: 8 bytes in 1 blocks ==24530== total heap usage: 1 allocs, 0 frees, 8 bytes allocated ==24530== ==24530== LEAK SUMMARY: ==24530== definitely lost: 0 bytes in 0 blocks ==24530== indirectly lost: 0 bytes in 0 blocks ==24530== possibly lost: 0 bytes in 0 blocks ==24530== still reachable: 8 bytes in 1 blocks ==24530== suppressed: 0 bytes in 0 blocks
Какие вещи я могу попытаться сделать с моим существующим кодом, чтобы полностью вернуть память операционной системе?
Для тестирования я использовал Blueberry Pi в операционной системе Linux. Кроме того, я использовал компилятор g++ и включил флаги-std=c++11, если это поможет.
Что я уже пробовал:
Я провел тщательное исследование по расшифровке утечек моей памяти, но либо то, что я нашел, было запрограммировано через c, либо не применимо в моей ситуации. Одна из проблем, которую я обнаружил, что потенциально я не инициализировал свои значения, и именно поэтому я получал эти ошибки. Однако после тщательной проверки я инициализирую все свои объявления в классе. Я смог проследить проблему до своего деструктора, по-видимому, он не освобождает память должным образом. Однако это может быть более глубокая проблема. Мой метод DeleteNode () при вызове в main способен освободить память, но я не знаю, как и почему он может это сделать, но не мой деструктор.
Обновление
Я пробовал различные методы, предложенные на этом форуме, но, к сожалению, это не сработало. Я подключился к различным Raspberry Pies, включая Blueberry, raspberry и pennutbutter для тестирования на моей виртуальной машине Linux, но всякий раз, когда я использую Valgrind для тестирования своего приложения, в дополнение к сообщению об ошибке, которое я уже показал, я также получаю незаконную инструкцию (не показано). Я также использовал Putty, но он имел тот же эффект. Однако я вроде как сдался, Visual Studio не сообщает, что у меня есть утечки, и вы, ребята, тоже, так что я, честно говоря, не знаю, и вы, ребята, похоже, не нашли ничего плохого в том, как я обрабатываю выделение памяти и освобождение, поэтому я не знаю.
Jochen Arndt
Я протестировал ваш код с Ubuntu, и он не сообщает об утечках памяти.
Тем не менее, похоже, что вы используете Raspberry Pi или другую встроенную систему на базе ARM. Вы можете добавить эту информацию и используемую командную строку G++ в свой вопрос, чтобы другие могли попытаться воспроизвести ошибку. Используйте зеленую ссылку "улучшить вопрос", чтобы отредактировать свой вопрос.
Mohibur Rashid
пара вопросов
если ваш mHead будет удален, вам также нужно установить mHead=nullptr, а также mCurr=nullptr
в противном случае он выдаст ошибку после удаления первого элемента. чтобы решить эту проблему, просто добавьте верификацию вверху, чтобы проверить, совпадает ли ваш поисковый элемент с mHead, и следуйте соответствующим инструкциям.
если вы добавляете новый элемент, убедитесь, что следующий элемент вашего нового элемента имеет значение nullptr, иначе многие вещи будут подвержены ошибкам.
Почему ваш mTemp является глобальным?
John Last
Хорошо, да, mTemp-это глобальная переменная. Я понимаю вашу точку зрения, я добавил проверку, поэтому всякий раз, когда я удалял новый узел, я проверял, является ли он головным узлом, и устанавливал его в nullptr, прежде чем начать удаление (на самом деле я просто обновил код, чтобы отразить это). Кроме того, по умолчанию любой новый узел, который я добавляю, это mNext, будет nullptr, а его данные равны 0. Я попробовал этот же код в visual studio 2015, и он не сообщает об утечках памяти, но когда я попробовал на виртуальной машине linux через терминал, он говорит, что я все еще утечка памяти.
Mohibur Rashid
Я не должен был называть переменную-член глобальной переменной. В любом случае
valgrind не показывает утечки памяти в ubuntu
== 19837 = = Memcheck, детектор ошибок памяти
== 19837 = = Copyright (C)2002-2015, и GNU GPL'D, Джулиан Сьюард и др.
==19837== с помощью Valgrind и-3.12.0 и LibVEX, повтор-с -ч авторских прав информация
= = 19837= = команда:. / output
==19837==
Значение 3 было удалено
5 ->
7 ->
5 был уничтожен.
7 был уничтожен.
==19837==
= = 19837 = = СВОДКА КУЧИ:
= = 19837== используется при выходе: 0 байт в 0 блоках
== 19837 = = общее использование кучи: 5 выделений, 5 освобождений, 73 776 выделенных байт
==19837==
= = 19837== все блоки кучи были освобождены - утечки невозможны
==19837==
= = 19837== для подсчета обнаруженных и подавленных ошибок выполните повторный запуск с помощью:- v
== 19837 = = сводка ошибок: 0 ошибок из 0 контекстов (подавлено: 0 из 0)
проверено также с помощью опции-v. Так что я ни о чем не догадываюсь