_Block_Type_Is_Valid(pHead-> nBlockUse)删除堆栈内存?

时间:2014-05-29 19:26:19

标签: c++ debugging pointers

我知道这是一个常见错误,所以我尝试创建一个最小的例子。我认为这是因为我试图释放堆栈内存,但我不太明白我可以做些不同的事情。

Maze.h

#pragma once
class Maze
{
    public:
        Maze();
        Maze(unsigned int height, unsigned int width);
        ~Maze();
    private:
        unsigned int m_height;
        unsigned int m_width;
        char *entrance;
        char *exit;
        char *m_cells;
};

Maze.cpp

#include "Maze.h"
using namespace std;

Maze::Maze()
{
}

Maze::Maze(unsigned int height, unsigned int width) :
    m_height(height),
    m_width(width)
{
    m_cells = new char[m_height * m_width];
    entrance = nullptr;
    exit = nullptr;
}

Maze::~Maze()
{
    delete entrance;
    delete exit;
    delete[] m_cells; //this line causes the error
}
导致错误的

main.cpp

#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;

int __cdecl main(int argc, char **argv)
{
    Maze maze;
    maze = Maze(10, 10);
}

main.cpp没有错误

#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;

int __cdecl main(int argc, char **argv)
{
    Maze maze(10, 10);
}

2个电源有什么区别?为什么第一个导致错误?这是一个问题,因为我想声明迷宫,但稍后在我的程序中初始化它。在这里,我只用两行来创建一个最小的例子。

当程序关闭时发生错误,所以我认为这是一个内存释放问题。的确,当我删除     delete [] m_cells; 来自析构函数,不再出错。

这里到底发生了什么?

1 个答案:

答案 0 :(得分:2)

该行:

maze = Maze(10, 10);

正在创建对象的副本,所以会发生什么:

  1. Maze(10, 10) - 构建一个新对象,使用operator newoperator new[]分配内存。
  2. 迷宫被分配了1中制作的对象的副本。这可以通过简单地将第一个指针值分配给第二个来完成。
  3. 然后从1中删除对象,删除指针。
  4. 迷宫最终超出范围,它会再次删除指针,在这里你崩溃。
  5. 要解决有关规则3的读数,您需要添加复制构造函数和赋值运算符。

    例如:

    // This the copy constructor
    Maze::Maze(const Maze& other)
    {
        // Call the assignment operator, saves duplicating the assignment operator code in here.
        *this = other;
    }
    
    // This is the assignment operator 
    Maze& Maze::operator = ( const Maze& other )
    {
        if ( this != &other )
        {
            // TODO: Copy your pointers, not by assigning them, but use operator new and copy the data as "other" will destruct and delete those pointers, hence your problem
        }
        return *this;
    }
    

    如果您使用的是C ++ 11,您也可以使用移动构造/赋值,然后只需交换指针,并将源对象指针设置为NULL / nullptr。

    在C ++ 11中,您还可以使用default和delete关键字来防止使用您不应该调用的构造函数,例如:

    class Foo
    {
    public:
       Foo() = default;
       // Prevent copying
       Foo(const Foo&) = delete;
       Foo& operator = ( const Foo& ) = delete;
       int x = 0;
    };
    

    这会导致以下内容在编译阶段失败:

    Foo a;
    a = Foo();