2015-10-06 3 views
0

У меня есть много кода, поэтому я попытаюсь сделать это как можно меньше, чтобы показать вам, ребята.Как правильно повторно использовать объект-указатель для пользовательского класса

Я пишу программу, которая пропускает память, мои усилия по очистке памяти приводят к сбою моей программы (только в Visual Studio, не используя MinGw). Я использую Visual Studio 2015 для отладки моего кода и вижу, сколько памяти я использую. Однако при добавлении ключевого слова delete, чтобы попытаться освободить некоторую память, Visual Studio запускает breakpont. Следуя точке останова, чтобы попытаться выяснить, что случилось, VS выводит меня на страницу с надписью «No Source Available».

Компиляция этого же кода с помощью MinGw gcc работает и выполняется отлично, однако мне нужен отладчик Visual Studio, поэтому я могу видеть использование своей памяти, чтобы я мог определить, исправлена ​​ли утечка или нет.

Я создаю много объектов динамически и переписываю им новые объекты. Мне нужна помощь в определении того, как удалить старую память, чтобы я мог хранить только в памяти вновь созданный объект.

Вот код, который я обеспокоен

StateNode *initState = nullptr;     // Pointer to the initial state 
StateNode *finishState = nullptr;    // Pointer to the final state 
bool finished = false;       // Flag for checking if the puzzle has completed  

size = getNumQueens(); 

// Make dynamic 2D array of the specified size 
char** init = new char*[size]; 
for (int i = 0; i < size; i++) 
    init[i] = new char[size]; 


// Puzzle main loop 
while (!finished) 
{  
    // Randomize the queens placement on the board 
    randomizeGame(init, size); 

    // Make the initial state with the current game board 
    initState = new StateNode(init, size); 

    // Run the hillclimbing algo 
    finishState = HillClimbing<StateNode>::Run(initState, size); 

    // Check to see if the algo returned a valid end state 
    if (finishState->getHeuristic() == 0) 
     finished = true; 
    else 
    { 
     // Try to clean up memory to prevent memory leak 
     delete initState; // This is where Visual Studio throws breakpoint 
     delete finishState; 
    } 
} 

Как вы можете видеть, это в то время как петля постоянно создает новые StateNode объекты, назначая их initState. Кроме того, метод HillClimbing::Run() возвращает динамически созданный StateNode и назначает его функции finishState.

Без этого кода:

else 
    { 
     // Try to clean up memory to prevent memory leak 
     delete initState; // This is where Visual Studio throws breakpoint 
     delete finishState; 
    } 

Моя программа просачивается много памяти, приближается к 2 Гб, когда программа падает. С этими строками VS выдает точки останова, но MinGw gcc не работает, и программа работает намного быстрее.

Мой главный вопрос: Как правильно управлять памятью initState и finishState для исправления утечек памяти.

i.e. Как я могу хранить только один объект StateNode, удаляя все остальные экземпляры, когда я иду.

EDIT Это то, что в окне вывода VS

The thread 0x4244 has exited with code 1857355776 (0x6eb50000). 
HEAP[N-Queens.exe]: Invalid address specified to RtlValidateHeap(,  0126B540) 
N-Queens.exe has triggered a breakpoint. 

При переходе в dissasembly и нажав клавишу F11, чтобы продолжать идти через код, в конце концов это происходит: enter image description here

EDIT 2

StateNode.h

class StateNode 
{ 
    private: 
     char** state; 
     int heuristic; 
     int size; 

    public: 
     StateNode(char** state, int size); 
     int getHeuristic(); 
     void printState(); 
     char** getState(); 
}; 

Вот код для StateNode.cpp

#include <iostream> 
#include "state-node.h" 
#include "heuristic.h" 

/* Constructor, accepts a state and a size (the number of queens) */ 
StateNode::StateNode(char ** state, int size) 
{ 
    this->state = state; 
    this->size = size; 
    this ->heuristic = NQueens::CalcHeuristic(state, size); 
} 



/* Returns the heuristic value of the node */ 
int StateNode::getHeuristic() 
{ 
    return this->heuristic; 
} 

/* Prints the state with a nice like board for better visualization */ 
void StateNode::printState() 
{ 
    for (int i = 0; i < this->size; i++) 
     std::cout << " ____"; 
    std::cout << std::endl; 

    for (int i = 0; i < this->size; i++) 
    { 
     for (int j = 0; j < this->size; j++) 
     { 
      if (j < this->size - 1) 
      { 

       std::cout << "| " << state[i][j] << " "; 

      } 
      else 
      { 

       std::cout << "| " << state[i][j] << " |"; 

      } 

     } 
     std::cout << std::endl; 
     for (int k = 0; k < this->size; k++) 
      std::cout << "|____"; 
     std::cout << "|\n"; 
    } 
} 

/* Returns a copy of the nodes state */ 
char ** StateNode::getState() 
{ 
    return state; 
} 
+0

Что находится в окне вывода VS, когда он останавливается при удалении? Существует множество случаев коррупционной памяти, которые вызовут остановку VS во время удаления/освобождения памяти. Обычно вы сбрасывали некоторые контрольные значения до или после выделенной памяти. – 1201ProgramAlarm

+0

Все ваши функции перекомпилированы из источника в вашем проекте? Или они живут в других библиотеках (например, DLL). Если они живут в других библиотеках, вы можете столкнуться с проблемой, когда память распределена в DLL, но вы освобождаете ее в основном, которая может использовать другую среду выполнения. –

+0

@ 1201ProgramAlarm see my edit – BradStell

ответ

2

Ваш текущий код выделяет динамически выделенную память, но не имеет единого понимания того, кто владеет указателями. Затем становится громоздким выяснить, когда, где и кто несет ответственность за освобождение памяти. Для исправления такого кода может потребоваться больше логики, подверженной ошибкам, чтобы попытаться выровнять беспорядок.

Вместо этого, используя C++ и «новый бескоммутаторная» код, следующий более или менее эквивалент текущего кода:

#include <vector> 
typedef std::vector<std::vector<char>> Char2D; 
class StateNode 
{ 
    private: 
     char2D state; 
     int size; 
     int heuristic; 

    public: 
     StateNode(const Char2D& theState, int theSize); 
     int getHeuristic(); 
     void printState(); 
     Char2D& getState() { return state; } 
}; 

Тогда ваш конструктор lools, как это:

StateNode::StateNode(const Char2D& theState, int theSize) : 
        state(theState), 
        size(theSize), 
        heuristic(NQueens::CalcHeuristic(state, size)) {} 

Конечно, ваш NQueens::CalcHeuristic должен принять Char2D (по ссылке) вместо char**.

Тогда остальная часть реализации может выглядеть следующим образом:

bool finished = false;  

size = getNumQueens(); 

// Make dynamic 2D array of the specified size 
Char2D init(size, std::vector<char>(size)); 

// Puzzle main loop 
while (!finished) 
{  
    // Randomize the queens placement on the board 
    randomizeGame(init, size); 

    // Make the initial state with the current game board 
    StateNode initState(init, size); 

    // Run the hillclimbing algo 
    finishState = HillClimbing<StateNode>::Run(initState, size); 

    // Check to see if the algo returned a valid end state 
    if (finishState.getHeuristic() == 0) 
     finished = true; 
} 

initState и finishState два различных объекта. Кроме того, нет необходимости в блоке else.

Я знаю, что это несколько отличается от исходного кода, но цель должна заключаться в использовании типов value и, если нужно, умных указателей (которых я здесь не видел). Использование типов, как упомянутых выше, является одним из способов не иметь проблем, с которыми вы сталкиваетесь сейчас.


Если вы все еще хотите, чтобы идти по пути указателя, я бы еще оставить в одиночку vector и внести следующие изменения:

#include <memory> 
//... 
std::unique_ptr<StateNode> finishState; 

// Puzzle main loop 
while (!finished) 
{  
    // Randomize the queens placement on the board 
    randomizeGame(init, size); 

    // Make the initial state with the current game board 
    std::unique_ptr<StateNode> initState = std::make_unique<StateNode>(init, size); 

    // Run the hillclimbing algo 
    finishState.reset(HillClimbing<StateNode>::Run(initState, size)); 

    // Check to see if the algo returned a valid end state 
    if (finishState->getHeuristic() == 0) 
     finished = true; 
} 

Там нет утечки в этом коде, так как мы используем std::unique_ptr, который автоматически освобождает память для вас, когда указатель выходит из области видимости или вызывается reset.

+0

Большое спасибо за этот пример. Позвольте мне потратить минуту, чтобы посмотреть, могу ли я перевести свой код на работу так, а затем я отчитаюсь. – BradStell

+0

Хорошо, я перевел код, и он не вызывает ошибок компиляции. Теперь мне нужна ваша помощь с последней частью кода, которая теперь не работает. Метод 'randomizeGame' используется для ввода' char ** 'и изменения массива. Вектор, похоже, не работает таким образом, и моя игровая панель остается пустой. – BradStell

+0

Я обновил ответ с помощью умной версии указателя вашего кода (с «std :: vector», остающимся на месте в объекте «StateNode».Вероятно, это то, что вы пытались сделать. – PaulMcKenzie

0

Вы можете отлаживать не по-источника доступного в вашем коде. Получить vs, чтобы показать разборку и f11 в следующую функцию.

Vs имеет отладочную кучу с обнаружением утечки. Это может помочь, но и привести к замедлению и раннему краху. Скомпилируйте с другой версией C, чтобы получить/проиграть эту функцию.

Верификатор приложения также имеет хорошее обнаружение утечки, показывающее стопки утечек. это то, что я использую

+0

Я просто попробовал это. К сожалению, я не понимаю разборки, это похоже на другой язык и не очень помогает мне. – BradStell

+0

Мой главный вопрос заключается не в том, как остановить VS от запуска точки останова, а в том, как правильно использовать память и остановить утечку памяти в первую очередь. – BradStell

+0

Просто нажмите f11, пока не дойдет до звонка. Затем он переходит к источнику – mksteve

Смежные вопросы