如何正确地重用指针对象到自定义类

时间:2015-10-06 00:45:23

标签: c++ visual-studio memory-leaks delete-operator

我有很多代码,所以我会尝试尽可能少地向你们展示这些代码。

我正在编写一个泄漏内存的程序,我清理内存的努力导致我的程序崩溃(仅在Visual Studio中,不使用MinGw)。我正在使用Visual Studio 2015来调试我的代码,并查看我正在使用多少内存。但是,在添加delete关键字以尝试释放某些内存时,Visual Studio会触发一个breakpont。当关注断点试图找出错误时,VS会将我带到一个“无源可用”的页面。

使用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;
    }
}   

正如您所看到的,此while循环通过将它们分配给initState来不断创建新的StateNode对象。此外,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;
    }

我的程序泄漏了大量内存,当程序崩溃时接近2GB。 使用这些线VS会抛出断点,但是MinGw gcc没有,并且程序运行得更快。

我的主要问题:如何正确管理initStatefinishState的内存以修复内存泄漏。

即。我如何只保留一个StateNode对象,同时删除所有其他实例。

修改 这是VS输出窗口中的内容

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

当进入dissasembly并按F11继续执行代码时,最终会发生这种情况: enter image description here

编辑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;
}

2 个答案:

答案 0 :(得分:2)

您当前的代码会分配动态分配的内存,但不具有谁拥有什么指针的连贯感。然后,弄清楚何时,何地以及谁负责释放内存变得很麻烦。修复这样的代码可能需要更多容易出错的逻辑来试图理清这些混乱。

而不是使用C ++和“new-less”代码,以下内容或多或少等同于您当前的代码:

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

然后你的构造函数就像这样:

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

initStatefinishState是两个不同的对象。此外,不需要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时,会自动为您释放内存。

答案 1 :(得分:0)

您可以通过no-source-available调试代码。获取vs将反汇编和f11显示为下一个函数。

Vs具有带泄漏检测的调试堆。这可能会有所帮助,但也会导致速度减慢,并且早先崩溃。使用不同的C运行时编译以获得/丢失该功能。

应用程序验证程序也具有良好的泄漏检测功能,显示泄漏分配的堆栈。 这是我使用的