【问题标题】:How do I fix this small memory leak for my program?如何为我的程序修复这个小内存泄漏?
【发布时间】:2017-05-09 17:03:57
【问题描述】:

所以我制作了一个模拟井字游戏的程序并用 valgrind 运行它,它说我有内存泄漏。是什么导致了这种泄漏,我该如何解决?

这是 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)

这里是代码:

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:

#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;
}

【问题讨论】:

    标签: c++ memory-leaks valgrind destructor


    【解决方案1】:

    所以,内存泄漏不是你的问题。这是程序初始化时发生的内存泄漏,甚至在您的任何代码执行之前。

    Valgrind 通常会忽略这些。它有一个文件,其中列出了在各种平台上的各种库中需要忽略的内容。也许你使用了一个 Valgrind 选项,告诉它不要忽略它们,或者它只是没有为该平台上那个确切版本的 libstdc++ 正确设置。

    作为一个不相关的 C++ 风格注释,我会说我不太喜欢你在 Board.h 中使用 #define。你应该声明const

    【讨论】:

    • 感谢您提供的信息。为什么你说我不应该在 Board.h 中使用#define?我是 C++ 新手,所以我不习惯该语言的常见约定。
    • @AnthonyPalumbo - 预处理器......好吧,被认为是丑陋的。将它用于#include 和(如果绝对必要)条件编译(#if#ifdef 等)。使用#define 是丑陋的,因为它完全践踏了范围规则和类型规则以及其他各种东西。 C++ 有内联函数。你可以说像const int foo = 5; 这样的东西,而不是#define foo 5foo 现在有一个类型,并被视为具有范围的适当标识符。为什么要避免预处理器实际上有点复杂。
    【解决方案2】:

    您的代码看起来不错,但我建议不要使用网格指针的指针,这有点难以处理。 而不是int **grid, 有int grid[SIZE][SIZE]。 那么你就不需要任何新的和删除的调用——没有内存泄漏的来源! 除非 SIZE 非常大并且您尝试在堆栈上分配 Board,否则此方法有效。如果 SIZE 很大,只需通过 b = new Board() 在堆上分配 Board。 (别忘了删除它!)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2017-06-28
      • 2011-10-09
      • 1970-01-01
      相关资源
      最近更新 更多