2016-12-24 9 views
1

그래서 Tic-Tac-Toe 게임을 시뮬레이트하고 valgrind로 실행 한 프로그램을 만들었습니다. 메모리 누수가 있다고합니다. 이 누수의 원인은 무엇이며 어떻게 수정합니까?내 작은 메모리 누수가 내 프로그램에 어떻게 수정합니까?

MAIN.CPP :

#include <iostream> 
#include "../include/Board.h" 

using namespace std; 

/** 
* Main function that is run. 
* @return: 0 on exit success 
*/ 
int main() { 
    Board b; 
    int r, c; 
    int moveCount = 0; 

    cout << "* * * * * Welcome to the Tic-Tac-Toe game! * * * * *" << endl; 
    cout << "Enter numbers 1, 2, or 3 when prompted for coordinates of your move." << endl; 
    cout << b.toString() << endl; 

    // Loops until there are no more possible moves. 
    while(moveCount < 9) { 
     // Prompts for coordinates to make a move. 
     do { 
      if(moveCount % 2 == 0) { 
       cout << "Player X's turn, enter the row and column of your move.\nRow #:"; 
      } 
      else { 
       cout << "Player O's turn, enter the row and column of your move.\nRow #:"; 
      } 
      cin >> r; 
      cout << "Column #:"; 
      cin >> c; 

      // Checks if the move is valid. 
      if(b.canPut((r - 1), (c - 1)) != 1) { 
       cout << "\nInvalid move, re-enter the desired coordinates.\n" << endl; 
      } 
     }while(b.canPut((r - 1), (c - 1)) != 1); 

     // Makes the move. 
     if(moveCount % 2 == 0) { 
      b.makeMove((r - 1), (c - 1), X); 
     } 
     else { 
      b.makeMove((r - 1), (c - 1), O); 
     } 

     cout << b.toString() << endl; 

     // Checks if there is a winner and breaks the loop if there is. 
     if(b.checkWinner() != 0) 
      break; 
     moveCount++; 
    } 

    // Prints the appropriate statement base on the winning status, if any. 
    if(moveCount == 9) { 
     cout << "\nGame over, stalemate." << endl; 
    } 
    else { 
     if(b.checkWinner() == X) { 
      cout << "\nPlayer X has won!!!" << endl; 
     } 
     else if(b.checkWinner() == O) { 
      cout << "\nPlayer O has won!!!" << endl; 
     } 
    } 

    return 0; 
} 

Board.h : 여기

는 Valgrind의로부터의 출력이다

==15253== 
==15253== HEAP SUMMARY: 
==15253==  in use at exit: 72,704 bytes in 1 blocks 
==15253== total heap usage: 37 allocs, 36 frees, 76,864 bytes allocated 
==15253== 
==15253== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1 
==15253== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==15253== by 0x4EC5B1F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22) 
==15253== by 0x40104E9: call_init.part.0 (dl-init.c:72) 
==15253== by 0x40105FA: call_init (dl-init.c:30) 
==15253== by 0x40105FA: _dl_init (dl-init.c:120) 
==15253== by 0x4000CF9: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so) 
==15253== 
==15253== LEAK SUMMARY: 
==15253== definitely lost: 0 bytes in 0 blocks 
==15253== indirectly lost: 0 bytes in 0 blocks 
==15253==  possibly lost: 0 bytes in 0 blocks 
==15253== still reachable: 72,704 bytes in 1 blocks 
==15253==   suppressed: 0 bytes in 0 blocks 
==15253== 
==15253== For counts of detected and suppressed errors, rerun with: -v 
==15253== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

및 여기 코드

#ifndef BOARD_H 
#define BOARD_H 

#include <string> 
#define X 1 
#define O 5 
#define SIZE 3 

/** 
* Board class for tic-tac-toe project. 
*/ 
class Board { 
    private: 
     int **grid; 
    public: 
     Board(); 
     ~Board(); 
     int checkWinner(); 
     int canPut(int r, int c); 
     void makeMove(int r, int c, int val); 
     std::string toString(); 
}; 

#endif 

Board.cpp :

#include "../include/Board.h" 
#include <string> 

using namespace std; 

/** 
* Constructor for a Board object. 
*/ 
Board::Board() { 
    grid = new int*[SIZE]; 

    // Creates all the 1D arrays to make the 2D array. 
    for(int ctr = 0; ctr < SIZE; ctr++) { 
     grid[ctr] = new int[SIZE]; 
     for(int i = 0; i < SIZE; i++) { 
      grid[ctr][i] = 0; 
     } 
    } 
} 

/** 
* Destructor for a Board object. 
*/ 
Board::~Board() { 
    for(int ctr = 0; ctr < SIZE; ctr++) { 
     delete[] grid[ctr]; 
    } 
    delete[] grid; 
} 

/** 
* Checks if there is a winner for the current game. 
* @return: 0 if no winner, X if X player wins or O if O player wins 
*/ 
int Board::checkWinner() { 
    int sum; 

    // Checks all the rows for a winner. 
    for(int i = 0; i < SIZE; i++) { 
     sum = 0; 
     for(int ctr = 0; ctr < SIZE; ctr++) { 
      sum += grid[i][ctr]; 
     } 
     if(sum == 3) { 
      return X; 
     } 
     else if(sum == 15) { 
      return O; 
     } 
    } 

    // Checks all the columns for a winner. 
    for(int a = 0; a < SIZE; a++) { 
     sum = 0; 
     for(int b = 0; b < SIZE; b++) { 
      sum += grid[b][a]; 
     } 
     if(sum == 3) { 
      return X; 
     } 
     else if(sum == 15) { 
      return O; 
     } 
    } 

    // Checks the top-left to bottom-right diagonal for a winner. 
    sum = 0; 
    for(int i = 0; i < SIZE; i++) { 
     sum += grid[i][i]; 
    } 
    if(sum == 3) { 
     return X; 
    } 
    else if(sum == 15) { 
     return O; 
    } 

    // Checks the top-right to bottom-left diagonal for a winner. 
    sum = 0; 
    for(int r = 0, c = SIZE - 1; r < SIZE && c > 0; r++, c--) { 
     sum += grid[r][c]; 
    } 
    if(sum == 3) { 
     return X; 
    } 
    else if(sum == 15) { 
     return O; 
    } 

    // Returns zero because after checking all the possibilities, a winner has not been found. 
    return 0; 
} 

/** 
* Determines if there is an open spot on the board at the given coordinates. 
* @param r: the row to be checked 
* @param c: the column to be checked 
* @return: 1 if there is an open spot, 0 if not 
*/ 
int Board::canPut(int r, int c) { 
    if(grid[r][c] == 0) 
     return 1; 
    return 0; 
} 

/** 
* Simulates making a move for a player. 
* @param r: the row to set the value 
* @param c: the column to set the value 
* @param val: the value to be set at the given coordinates 
*/ 
void Board::makeMove(int r, int c, int val) { 
    grid[r][c] = val; 
} 

/** 
* Creates a representation of the board as a string. 
* @return: string of the board 
*/ 
string Board::toString() { 
    char a, b, c; 
    string output = "Board:\n"; 

    // Loops through every line for the 2D array. 
    for(int ctr = 0; ctr < SIZE; ctr++) { 

     // Loops through every value of the 1D array being checked. 
     for(int i = 0; i < SIZE; i++) { 
      output += ' '; 
      if(grid[ctr][i] == X) { 
       output += 'X'; 
      } 
      else if(grid[ctr][i] == O) { 
       output += 'O'; 
      } 
      else { 
       output += ' '; 
      } 
      if(i != (SIZE - 1)) { 
       output.append(" |"); 
      } 
      else { 
       output += '\n'; 
      } 
     } 

     // Pads each line with a line of '-' characters. 
     if(ctr != (SIZE - 1)) { 
      for(int i = 0; i < (SIZE * 4) - 1; i++) { 
       output += '-'; 
      } 
      output += '\n'; 
     } 
    } 
    return output; 
} 

답변

2

그래서 메모리 누수는 문제가 아닙니다. 프로그램이 초기화를 수행 할 때, 심지어 코드가 실행되기 전에 발생하는 메모리 누수입니다.

일반적으로 Valgrind는이를 무시합니다. 그것은 다양한 플랫폼에서 다양한 라이브러리에서 무시할 필요가있는 것들의 목록을 가지고있는 파일을 가지고 있습니다. 아마 그들을 무시하지 말라고 말한 Valgrind 옵션을 사용했을 수도 있습니다. 아니면 아마도 해당 플랫폼에서 libstdC++의 정확한 버전을 위해 올바르게 설정되지 않았을 것입니다.

관련없는 C++ 스타일 메모로 #defineBoard.h에 사용했다는 점이 마음에 들지 않습니다. 너는 const 것을 선언해야한다.

+0

감사합니다. 왜 당신은 Board.h에서'# define'을 사용하지 말아야한다고 말합니까? 나는 C++을 처음 사용하므로 언어의 일반적인 규칙에 익숙하지 않다. –

+0

@AnthonyPalumbo - 전처리 기는 ... 글쎄, 추악한 것으로 간주됩니다. '# include'와 (꼭 필요한 경우) 조건부 컴파일 ('# if'와'# ifdef' 등)에 사용하십시오. '# define'을 사용하는 것은 범위 규칙과 형식 규칙 및 다양한 다른 것들을 완전히 짓밟 기 때문에 추악합니다. C++에는 인라인 함수가 있습니다. 그리고 여러분은'#define foo 5' 대신에'const int foo = 5;'와''foo''가 타입을 가지며 범위가있는 적절한 식별자처럼 취급 될 수 있다고 말할 수 있습니다. 전 처리기가 피해야하는 이유는 실제로 복잡합니다. – Omnifarious

2

코드가 좋아 보이지만 처리하기에 약간 까다로운 그리드 포인터 포인터를 사용하지 말 것을 제안합니다. int **grid 대신 은 int grid[SIZE][SIZE]입니다. 그런 다음 새롭고 삭제 된 호출이 필요하지 않습니다. 메모리 누수가 없습니다! 크기가 매우 커서 보드를 스택에 할당하려고 시도하지 않으면이 방법이 효과적입니다. SIZE가 크면 힙에 보드를 b = new Board()만큼 할당하십시오. (삭제하는 것을 잊지 마세요!)