Dangling memory/ unallocated memory issue - c++

I've this piece of code, which is called by a timer Update mechanism.
However, I notice, that the memory size of the application, while running, continuously increases by 4, indicating that there might be a rogue pointer, or some other issue.
void RtdbConnection::getItemList()
{
std::vector<CString> tagList = mItemList->getItems();
//CString str(_T("STD-DOL1"));
PwItemList* pil = mPwSrv->GetItemList();
CPwItem pw ;
for(auto it = tagList.begin(); it != tagList.end(); ++it)
{
pw = mPwSrv->GetItem(*it);
pil->AddItem(&(PwItem)pw);
}
pil->AddInfo(DB_DESC); //Description
pil->AddInfo(DB_QALRM); // Alarm Status
pil->AddInfo(DB_QUNAK); //UNACK status
pil->AddInfo(DB_AL_PRI); // Priority of the alarm tag
pil->ExecuteQuery();
int i = 0;
for (auto it = tagList.begin(); i < pil->GetInfoRetrievedCount() && it != tagList.end(); i+=4, it++)
{
//item = {0};
CString str(*it);
PwInfo info = pil->GetInfo(i);
CString p(info.szValue().c_str());
bool isAlarm = pil->GetInfo(i+1).bValue();
bool isAck = pil->GetInfo(i+2).bValue();
int priority = pil->GetInfo(i+3).iValue();
item = ItemInfo(str, p, isAlarm, isAck, priority);
//int r = sizeof(item);
mItemList->setInfo(str, item); // Set the details for the item of the List
}
delete pil;
pil = NULL;
}
I cannot seem to find a memory block requiring de-allocation here. Nor is there any allocation of memory when I step inside the following function :
mItemList->setInfo(str, item);
which is defined as :
void ItemList::setInfo(CString tagname, ItemInfo info)
{
int flag = 0;
COLORREF tempColour;
std::map<CString, ItemInfo>::iterator tempIterator;
if ( (tempIterator = mAlarmListMap.find(tagname)) !=mAlarmListMap.end() )
{
//remove the current iteminfo and insert new one
if(mAlarmListMap[tagname].getPriority() != info.getPriority() && (mAlarmListMap[tagname].getPriority()!=0))
{
mAlarmListMap[tagname].updatePriority(info.getPriority());
mAlarmListMap[tagname].mPrioChanged = TRUE;
}
else
{
mAlarmListMap[tagname].mPrioChanged = FALSE;
((mAlarmListMap[tagname].getPrevPriority() != 0)?(mAlarmListMap[tagname].ResetPrevPriority()):TRUE);
mAlarmListMap[tagname].setPriority(info.getPriority());
}
mAlarmListMap[tagname].setDescription(info.getDescription());
mAlarmListMap[tagname].setAlarm(info.getAlarmStat());
mAlarmListMap[tagname].setAlarmAck(info.getAckStat());
tempColour = mColourLogic->setUpdatedColour(mAlarmListMap[tagname].getAlarmStat(), mAlarmListMap[tagname].getAckStat(), flag);
mAlarmListMap[tagname].setColour(tempColour);
if(!(info.getAlarmStat() || info.getAckStat()))
{
flag = 1;
mAlarmListMap[tagname].mIsRTN = true;
mAlarmListMap[tagname].setDisplayCondition(false);
}
else
{
mAlarmListMap[tagname].setDisplayCondition(true);
}
//((mAlarmListMap[tagname].mIsRTN == true)?
}
else
{
tempIterator = mAlarmListMap.begin();
tempColour = mColourLogic->fillColourFirst(info.getAlarmStat(), info.getAckStat());
info.setColour(tempColour);
mAlarmListMap.insert(tempIterator, std::pair<CString,ItemInfo>(tagname,info));
}
}
I tried juggling with the allocations, but the increase is always a constant 4.
Could anyone kindly look and highlight where the issue could be?
Thanks a lot.

Related

How to get multiple selected values from listbox in mfc

I am making a music player program using MFC.
I would like to add a function to select multiple values ​​in the listbox and delete them, but I would like to ask for advice.
The option of the listbox is Extended, and multiple selection using the control keys is fine.
Among the methods of listbox, it seems to be possible to use SetSel, GetCursel, GetSelItems, etc, but I can't solve it.
I would appreciate it if you could give me a simple advice.
Thank you very much.
void CMFC_MP3Dlg::DeleteList(CStatus* head)
{
CFileFind finder;
CString strTemp;
CString strRemoveFile;
POSITION pos;
CStatus* pTemp = new CStatus();
CStatus* pPrev = new CStatus();
//int nSelCount = m_ListBox.GetCurSel();
//m_ListBox.GetText(nSelCount, strTemp);
LPINT lpSelItems = new int[m_nListBoxCount];
m_ListBox.GetSelItems(m_nListBoxCount, lpSelItems);
for (int nCount = 0; nCount <= m_nListBoxCount; nCount ++)
{
if(m_ListBox.SetSel(nCount,1))
{
m_ListBox.GetText(nCount, strTemp);
m_vec.push_back(strTemp);
}
}
std::vector<CString>::iterator iter;
for(iter = m_vec.begin(); iter != m_vec.end();)
{
strRemoveFile.Format(_T("C:\\MFC_MP3\\%s"), *iter);
BOOL bRet = finder.FindFile(strRemoveFile);
if(bRet)
{
if(DeleteFile(strRemoveFile))
{
pPrev = NULL;
pTemp = head;
if(pTemp == NULL)
{
return;
}
while(pTemp->m_strFileName != strTemp)
{
pPrev = pTemp;
pTemp = pTemp->m_right;
}
if(pTemp->m_strFileName == strTemp)
{
pPrev->m_right = pTemp->m_right;
pTemp->m_right->m_left = pPrev;
delete pTemp;
}
MessageBox(_T("삭제 성공!"));
ShowList();
}
else
{
MessageBox(_T("삭제 실패!"));
}
}
else
{
MessageBox(_T("File Not Found!"));
}
iter++;
}
}
Does this help?
void CChristianLifeMinistryPersonalCopiesDlg::BuildSelectedArray()
{
int i, iSize, *pIndex;
CString strText;
m_aryStrPublishers.RemoveAll();
// get selected count
iSize = m_lbPublishers.GetSelCount();
if (iSize > 0)
{
pIndex = new int[iSize];
m_lbPublishers.GetSelItems(iSize, pIndex);
for (i = 0; i < iSize; i++)
{
m_lbPublishers.GetText(pIndex[i], strText);
m_aryStrPublishers.Add(strText);
}
delete[] pIndex;
}
}
This works fine for me.
Note that your code is incomplete though. We don't see you specify what the count is of the selected items. And we don't see you reset your vector array before you begin.
Have you actually debugged your code to see where it fails?

Creating a second instance of an object changes whole class behavior (C++)

I have written an Arduino library in C++ that contains an iterator class. If I iterate through it using the same instance all the time, it works as expected. If I create a second instance to do so, it will double the amount of stored objects.
WayPointStack wps = *(new WayPointStack());
wps.AddWP(1, 20);
wps.AddWP(2, 420);
WPCommand c1 = wps.GetNextWP(); // Stack length: 2, correct
c1 = wps.GetNextWP(); //
WPCommand c1 = wps.GetNextWP(); // Stack length: 4, not correct
WPCommand c2 = wps.GetNextWP(); //
WPCommand WayPointStack::GetNextWP()
{
Serial.println("Pointer = ");
Serial.println(pointer);
Serial.println("Length = ");
Serial.println(_length);
if (pointer < _length){
pointer++;
return _wp[pointer-1];
}
return *(new WPCommand(_END, 10000));
}
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length] = *(new WPCommand(target, time));
_length++;
}
WayPointStack::WayPointStack()
{
_wp = new WPCommand[arrSize];
_length = 0;
pointer = 0;
}
WPCommand::WPCommand(int target, int time)
{
_target = target;
_time = time;
}
Can someone explain this to me?
WayPointStack wps = *(new WayPointStack());
must be
WayPointStack wps;
because it is enough and that removes the memory leak
In
WPCommand WayPointStack::GetNextWP()
{
...
return *(new WPCommand(_END, 10000));
}
you create an other memory leak, may be do not return the element but its address allowing you to return nullptr on error ?
/*const ?*/ WPCommand * WayPointStack::GetNextWP()
{
Serial.println("Pointer = ");
Serial.println(pointer);
Serial.println("Length = ");
Serial.println(_length);
if (pointer < _length){
return &_wp[pointer++];
}
return nullptr;
}
else use a static var :
WPCommand WayPointStack::GetNextWP()
{
...
static WPCommand error(_END, 10000);
return error;
}
In
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length] = *(new WPCommand(target, time));
_length++;
}
you create an other memory leak, you just need to initialize the entry :
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length]._target = target, time));
_wp[_length]._time = time;
_length++;
}
you do not signal the error when you cannot add a new element, what about to return a bool valuing false on error and true when you can add :
bool WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return false;
_wp[_length]._target = target;
_wp[_length]._time = time;
_length++;
return true;
}
Finally Why do you not use a std::vector for _wp
It looks like you have a memory leak on this line:
return *(new WPCommand(_END, 10000));
It looks like you are creating WPCommand on heap, then throw away pointer and return a copy !!!
The example is not minimal and complete so it is hard to give better pointers.

C++ linked list has junk nodes appearing in it [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
When implementing a call stack trace for tracking allocation in my overridden new function, I am using ::malloc to create an untracked call stack object that is then put into a linked list. When my harness finishes new-ing off all of the test cases, the list is sound. However, when i go to report the list (print to console) there are now values that should not be there and are causing it to crash. Below is the simplified version (I apologize that even simplified it is still a lot of code), I am hoping someone can make since of this:
Macros
#define convertToKiB(size) size * 1024UL
#define convertToMiB(size) size * (1024UL * 1024UL)
#define convertToGiB(size) size * (1024UL * 1024UL * 1024UL)
#define convertToReadableBytes(size) ((uint32_t)size > convertToKiB(2) && (uint32_t)size < convertToMiB(2)) ? (float)size / (float)convertToKiB(1) : ((uint32_t)size > convertToMiB(2) && (uint32_t)size < convertToGiB(2)) ? (float)size / (float)convertToMiB(1) : ((uint32_t)size > convertToGiB(2)) ? (float)size / (float)convertToMiB(1) : (float)size
#define convertToReadableBytesString(size) ((uint32_t)size > convertToKiB(2) && (uint32_t)size < convertToMiB(2)) ? "KiB" : ((uint32_t)size > convertToMiB(2) && (uint32_t)size < convertToGiB(2)) ? "MiB" : ((uint32_t)size > convertToGiB(2)) ? "GiB" : "B"
Globals
const uint8_t MAX_FRAMES_PER_CALLSTACK = 128;
const uint16_t MAX_SYMBOL_NAME_LENGTH = 128;
const uint32_t MAX_FILENAME_LENGTH = 1024;
const uint16_t MAX_DEPTH = 128;
typedef BOOL(__stdcall *sym_initialize_t)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
typedef BOOL(__stdcall *sym_cleanup_t)(IN HANDLE hProcess);
typedef BOOL(__stdcall *sym_from_addr_t)(IN HANDLE hProcess, IN DWORD64 Address, OUT PDWORD64 Displacement, OUT PSYMBOL_INFO Symbol);
typedef BOOL(__stdcall *sym_get_line_t)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Symbol);
static HMODULE g_debug_help;
static HANDLE g_process;
static SYMBOL_INFO* g_symbol;
static sym_initialize_t g_sym_initialize;
static sym_cleanup_t g_sym_cleanup;
static sym_from_addr_t g_sym_from_addr;
static sym_get_line_t g_sym_get_line_from_addr_64;
static int g_callstack_count = 0;
static callstack_list* g_callstack_root = nullptr;
CallStack Object
struct callstack_line_t
{
char file_name[128];
char function_name[256];
uint32_t line;
uint32_t offset;
};
class CallStack
{
public:
CallStack();
uint32_t m_hash;
uint8_t m_frame_count;
void* m_frames[MAX_FRAMES_PER_CALLSTACK];
};
CallStack::CallStack()
: m_hash(0)
, m_frame_count(0) {}
bool CallstackSystemInit()
{
// Load the dll, similar to OpenGL function fecthing.
// This is where these functions will come from.
g_debug_help = LoadLibraryA("dbghelp.dll");
if (g_debug_help == nullptr) {
return false;
}
// Get pointers to the functions we want from the loded library.
g_sym_initialize = (sym_initialize_t)GetProcAddress(g_debug_help, "SymInitialize");
g_sym_cleanup = (sym_cleanup_t)GetProcAddress(g_debug_help, "SymCleanup");
g_sym_from_addr = (sym_from_addr_t)GetProcAddress(g_debug_help, "SymFromAddr");
g_sym_get_line_from_addr_64 = (sym_get_line_t)GetProcAddress(g_debug_help, "SymGetLineFromAddr64");
// Initialize the system using the current process [see MSDN for details]
g_process = ::GetCurrentProcess();
g_sym_initialize(g_process, NULL, TRUE);
// Preallocate some memory for loading symbol information.
g_symbol = (SYMBOL_INFO *) ::malloc(sizeof(SYMBOL_INFO) + (MAX_FILENAME_LENGTH * sizeof(char)));
g_symbol->MaxNameLen = MAX_FILENAME_LENGTH;
g_symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
return true;
}
void CallstackSystemDeinit()
{
// cleanup after ourselves
::free(g_symbol);
g_symbol = nullptr;
g_sym_cleanup(g_process);
FreeLibrary(g_debug_help);
g_debug_help = NULL;
}
// Can not be static - called when
// the callstack is freed.
void DestroyCallstack(CallStack *ptr)
{
::free(ptr);
}
CallStack* CreateCallstack(uint8_t skip_frames)
{
// Capture the callstack frames - uses a windows call
void *stack[MAX_DEPTH];
DWORD hash;
// skip_frames: number of frames to skip [starting at the top - so don't return the frames for "CreateCallstack" (+1), plus "skip_frame_" layers.
// max_frames to return
// memory to put this information into.
// out pointer to back trace hash.
uint32_t frames = CaptureStackBackTrace(1 + skip_frames, MAX_DEPTH, stack, &hash);
// create the callstack using an untracked allocation
CallStack *cs = (CallStack*) ::malloc(sizeof(CallStack));
// force call the constructor (new in-place)
cs = new (cs) CallStack();
// copy the frames to our callstack object
unsigned int frame_count = min(MAX_FRAMES_PER_CALLSTACK, frames);
cs->m_frame_count = frame_count;
::memcpy(cs->m_frames, stack, sizeof(void*) * frame_count);
cs->m_hash = hash;
return cs;
}
//------------------------------------------------------------------------
// Fills lines with human readable data for the given callstack
// Fills from top to bottom (top being most recently called, with each next one being the calling function of the previous)
//
// Additional features you can add;
// [ ] If a file exists in yoru src directory, clip the filename
// [ ] Be able to specify a list of function names which will cause this trace to stop.
uint16_t CallstackGetLines(callstack_line_t *line_buffer, const uint16_t max_lines, CallStack *cs)
{
IMAGEHLP_LINE64 line_info;
DWORD line_offset = 0; // Displacement from the beginning of the line
line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
unsigned int count = min(max_lines, cs->m_frame_count);
unsigned int idx = 0;
for (unsigned int i = 0; i < count; ++i) {
callstack_line_t *line = &(line_buffer[idx]);
DWORD64 ptr = (DWORD64)(cs->m_frames[i]);
if (FALSE == g_sym_from_addr(g_process, ptr, 0, g_symbol)) {
continue;
}
strcpy_s(line->function_name, 256, g_symbol->Name);
BOOL bRet = g_sym_get_line_from_addr_64(
GetCurrentProcess(), // Process handle of the current process
ptr, // Address
&line_offset, // Displacement will be stored here by the function
&line_info); // File name / line information will be stored here
if (bRet)
{
line->line = line_info.LineNumber;
strcpy_s(line->file_name, 128, line_info.FileName);
line->offset = line_offset;
}
else {
// no information
line->line = 0;
line->offset = 0;
strcpy_s(line->file_name, 128, "N/A");
}
++idx;
}
return idx;
}
Operators
// Treat as Linked List Node
struct callstack_list
{
CallStack* current_stack = nullptr;
uint16_t total_allocation = 0;
callstack_list* next = nullptr;
};
struct allocation_meta
{
uint16_t size;
callstack_list callstack_node;
};
void* operator new(const size_t size)
{
uint16_t alloc_size = (uint16_t)size + (uint16_t)sizeof(allocation_meta);
allocation_meta *ptr = (allocation_meta*)::malloc((size_t)alloc_size);
ptr->size = (uint16_t)size;
ptr->callstack_node.current_stack = CreateCallstack(0);
ptr->callstack_node.total_allocation = (uint16_t)size;
ptr->callstack_node.next = nullptr;
bool run = true;
callstack_list* currentNode = nullptr;
while (g_callstack_root != nullptr && run)
{
if (currentNode == nullptr)
{
currentNode = g_callstack_root;
}
if (currentNode->next != nullptr)
{
currentNode = currentNode->next;
}
else
{
currentNode->next = &ptr->callstack_node;
run = false;
}
}
if (g_callstack_root == nullptr)
{
g_callstack_root = &ptr->callstack_node;
}
return ptr + 1;
}
void operator delete(void* ptr)
{
if (nullptr == ptr)
return;
allocation_meta *data = (allocation_meta*)ptr;
data--;
if (data->callstack_node.current_stack != nullptr)
DestroyCallstack(data->callstack_node.current_stack);
bool run = true;
callstack_list* currentNode = nullptr;
while (g_callstack_root != nullptr && run && &data->callstack_node != NULL)
{
if (currentNode == nullptr && g_callstack_root != &data->callstack_node)
{
currentNode = g_callstack_root;
}
else
{
g_callstack_root = nullptr;
run = false;
continue;
}
if (currentNode->next != nullptr && currentNode->next != &data->callstack_node)
{
currentNode = currentNode->next;
}
else
{
currentNode->next = nullptr;
run = false;
}
}
::free(data);
}
Test Harness
void ReportVerboseCallStacks(const char* start_time_str = "", const char* end_time_str = "")
{
callstack_list* currentNode = g_callstack_root;
unsigned int totalSimiliarAllocs = 0;
uint32_t totalSimiliarSize = 0;
while (currentNode != nullptr)
{
callstack_list* nextNode = currentNode->next;
uint32_t& currentHash = currentNode->current_stack->m_hash;
uint32_t nextHash;
if (nextNode == nullptr)
nextHash = currentHash + 1;
else
nextHash = nextNode->current_stack->m_hash;
if (nextHash == currentHash)
{
totalSimiliarSize += currentNode->total_allocation;
totalSimiliarAllocs++;
}
if (nextHash != currentHash)
{
//Print total allocs for type and total size
float reportedBytes = convertToReadableBytes(totalSimiliarSize);
std::string size = convertToReadableBytesString(totalSimiliarSize);
char collection_buffer[128];
sprintf_s(collection_buffer, 128, "\nGroup contained %s allocation(s), Total: %0.3f %s\n", std::to_string(totalSimiliarAllocs).c_str(), reportedBytes, size.c_str());
printf(collection_buffer);
//Reset total allocs and size
totalSimiliarAllocs = 0;
totalSimiliarSize = 0;
}
// Printing a call stack, happens when making report
char line_buffer[512];
callstack_line_t lines[128];
unsigned int line_count = CallstackGetLines(lines, 128, currentNode->current_stack);
for (unsigned int i = 0; i < line_count; ++i)
{
// this specific format will make it double click-able in an output window
// taking you to the offending line.
//Print Line For Call Stack
sprintf_s(line_buffer, 512, " %s(%u): %s\n", lines[i].file_name, lines[i].line, lines[i].function_name);
printf(line_buffer);
}
currentNode = currentNode->next;
}
}
void Pop64List(int64_t* arr[], int size)
{
for (int index = 0; index < size; ++index)
{
arr[index] = new int64_t;
*arr[index] = (int64_t)index;
}
}
void Pop8List(int8_t* arr[], int size)
{
for (int index = 0; index < size; ++index)
{
arr[index] = new int8_t;
*arr[index] = (int8_t)index;
}
}
int main()
{
if (!CallstackSystemInit())
return 1;
const int SIZE_64 = 8000;
int64_t* arr_64[SIZE_64];
const int SIZE_8 = 10000;
int8_t* arr_8[SIZE_8];
Pop64List(arr_64, SIZE_64);
Pop8List(arr_8, SIZE_8);
ReportVerboseCallStacks();
CallstackSystemDeinit();
return 0;
}
I finally figured out the answer. In my reporting function I was using std::string to create some of the reporting objects. std::string calls ::new internally to create a small allocation, and then hammers additional memory as the string's internal array reallocates memory. Switching to C-strings solved my problem.

C++ memory leak, where?

I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.

Extending python3, how does the garbage collection work

I'm making my own PriorityQueue in C as a python module. I read the basics of python ownership and reference system, so I thought I'd do the following:
In push(): Accept an priority(int) and an object to be saved. Increment the reference count on the object to be saved, since we will be keeping that.
In pop(): Delete the object from my priorityqueue, but don't decrement the reference counter, since that might destroy the object. Instead I transfer my reference ownership to the python function calling my function.
This seemed to work at first hand. But when actually using it in an application I get the following error:
Fatal Python error: GC object already tracked
What does this mean? The stacktrace is not useful at all, it's all inside python files I don't recognize(sre_parse and apport_python_hook).
Just for clarity, these are my C push and pop functions:
(self->heap[index]->key is the priority of the element at that index
self->heap[index]->value is the object)
PyObject* pop(CDSHeap *self) {
//If there aare no elements
if (self->heap[0].value == 0 || self->end == 0) {
Py_RETURN_NONE;
}
//If there is only one element
if (self->end == 1) {
PyObject* result = self->heap[0].value;
self->heap[0].key = 0;
self->end = 0;
return result;
}
//Two or more elements:
//First save the result:
PyObject* result = self->heap[0].value;
//Get the last element, and place it at the top
while (self->heap[self->end].value == 0) self->end--;
self->heap[0].value = self->heap[self->end].value;
self->heap[0].key = self->heap[self->end].key;
self->heap[self->end].value = 0;
//Reheapify the heap
int ptr = 0;
while (self->end >= ptr) {
if (self->heap[ptr*2+1].value != 0 && self->heap[ptr*2+1].key < self->heap[ptr].key
&& (self->heap[ptr*2+2].value == 0 || self->heap[ptr*2+1].key <= self->heap[ptr*2+2].key)) {
swapElement(self->heap, ptr, ptr*2+1);
ptr = ptr*2+1;
}else
if (self->heap[ptr*2+2].value != 0 && self->heap[ptr*2+2].value < self->heap[ptr].value) {
swapElement(self->heap, ptr, ptr*2+2);
ptr = ptr*2+2;
} else {
break;
}
}
return result;
}
PyObject* push(CDSHeap *self, PyObject* args) {
int k;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO",&k, &obj)){
return NULL;
}
Py_INCREF(obj);
//Add the element to the end of the heap
self->heap[self->end].key = k;
self->heap[self->end].value = obj;
//Increment the size and reheapify
int ptr = self->end++;
while (ptr > 0) {
int parent = (ptr-1)/2;
if (self->heap[ptr].key < self->heap[parent].key) {
swapElement(self->heap, ptr, parent);
ptr = parent;
} else {
Py_RETURN_NONE;
}
}
Py_RETURN_NONE;
}