0

I know this is a common error so I tried to create a minimal example. I think this is because I try to free stack memory but I don't quite understand how I could do differently.

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 that causes an error

#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 without error

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

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

What are the differences between the 2 mains ? why does the first one cause an error ? This is a problem because I want to declare maze but to initialize it later in my program. Here I only do it in two lines to create a minimal example.

The error occurs when the program closes so I think it's a memory deallocation problem. Indeed, when I remove delete[] m_cells; from the destructor, no error anymore.

What's happening exactly here ?

Kalissar
  • 119
  • 1
  • 5
  • In none of the other questions concerning the BLOCK_TYPE the answer was "redefine the copy constructor" so I don't see why it's a duplicate – Kalissar May 29 '14 at 20:12

1 Answers1

2

The line:

maze = Maze(10, 10);

Is creating a copy of the object, so what happens is:

  1. Maze(10, 10) - constructs a new object, who allocates memory with operator new and operator new[].
  2. maze is assigned a copy of the object made in 1. This is done by simply assigning the pointer values of the first to the 2nd.
  3. Then the object from 1 is destructed, it deletes the pointers.
  4. maze eventually goes out of scope, it deletes the pointers again, here you crash.

To solve this read about the rule of 3, you need to add a copy constructor and an assignment operator.

For example:

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

If you are using C++11 you could also use move construction/assignment too, then you would simply swap the pointers, and set the source objects pointers to NULL/nullptr.

In C++11 you can also use the default and delete keyword to prevent use of constructors you have no implemented that shouldn't be called, for example:

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

This would cause the following to fail at the compilation stage:

Foo a;
a = Foo(); 
paulm
  • 5,629
  • 7
  • 47
  • 70
  • And in the assignment operator, I use the copy constructor that I just redefined ? – Kalissar May 29 '14 at 19:36
  • strangely enough, (other != &this) doesn't compile but (this != &other) does. I found (this != &other) [here](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). Is it normal ? – Kalissar May 29 '14 at 20:31
  • Yeah sorry, I didn't compile any of this code, I'll fix that :) – paulm May 29 '14 at 21:08