This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 2 years ago.
I'm doing a matrix-product exercise (strassen's algorithm actually) using C++. Since the biggest data set given reaches 2048 * 2048, I tried to free the temp memory using delete[]. But it says there is a memory access violation in it, why?
Here are some of the code that may help:
struct Matrix {
int row, column;
int** m;
Matrix(int row, int column) {
m = new int* [2048];
for (int i = 0; i < row; i++)
m[i] = new int[2048];
}
~Matrix() {
if (m != NULL) {
for (int i = 0; i < 2048; i++) {
delete[] m[i]; //access violation happens here
}
delete[] m;
}
}
};
Matrix matAdd(Matrix matA, Matrix matB) {
Matrix matR = Matrix(matA.row, matA.column);
for (int i = 0; i < matA.row; i++)
for (int j = 0; j < matA.column; j++) {
matR.m[i][j] = matA.m[i][j] + matB.m[i][j];
}
return matR;
}
//There are some other functions below but the structure is basically the same
The pointers in the array, starting from the index row were not initialized.
Matrix(int row, int column) {
m = new int* [2048];
for (int i = 0; i < row; i++)
m[i] = new int[2048];
// Initialize rest elements with null pointer.
for (int i = row; i < 2048; i++)
m[i] = nullptr;
}
The rest initialization will fix the crash, but then you will get crash on double free. The reason: you use copies of your class, thus you need to implement the copy constructor and the assignment operator or use shared pointers instead of raw pointers. The default copy makes pointers pointing to the same allocated objects.
Also look at the answer https://stackoverflow.com/a/1403180/6752050 with the example how to create a 2d matrix with a single allocation.
You should consider using std::vector<std::vector<int>>.
Your class is lacking copy constructor and copy assignment and I am certain it is a case of double free.
Related
I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...
I am currently learning how to utilize raw pointers in C++. I understand how to dynamically allocate a 2D array, however, as an exercise for myself, I attempted to apply my understanding of multiple levels of indirection to allocate a 3D array. My attempt is presented below:
int main() {
double*** matrix { new double**[10] {} };
for (size_t i {}; i < 10; ++i) {
matrix[i] = new double*[i + 1] {};
for(size_t j {}; j < 10; ++j) {
matrix[i][j] = new double[i + 1] {};
}
}
std::cout << matrix[0][0][0] << std::endl;
for (size_t i {}; i < 10; ++i) {
for (size_t j {}; j < 10; ++j) {
delete[] matrix[i][j];
matrix[i][j] = nullptr;
}
delete[] matrix[i];
matrix[i] = nullptr;
}
delete[] matrix;
matrix = nullptr;
return 0;
}
Since I'm using uniform initialization, matrix[0][0][0] should print the value 0.0; However, I'm getting a garbage value when doing so. Furthermore, I have a double free or corruption (out) error, which I assume is telling me that I am attempting to free memory from the same address twice.
Any help or guidance would be appreciated. I'm just trying to fully understand raw pointers.
Edit: I understand that double*** is not actually a 3D array. I'm just trying to utilize simple terminology.
matrix[i] = new double*[i + 1] {};
for(size_t j {}; j < 10; ++j) {
This is your error right here, you allocate an array of 'i + 1' element and then loop for 10, you either need to have i + 1 in both places or 10 otherwise this is undefined behavior. The same applies for deletion (the loop checks for 10 but you only allocated i + 1).
I get an error "munmap_chunk(): invalid pointer", I don't know why. Problem appears when I use MultipliedByMatrix method. It can't properly delete the matrix that was created in this method.
#include "matrix.h"
Matrix::Matrix(int matr_size) {
size = matr_size;
Matr = new int *[size];
for(int i = 0; i < size; i++)
Matr[i] = new int[size];
for(int i = 0 ; i < size; i++)
for(int j = 0; j < size; j++)
Matr[i][j] = rand() % 100;
std::cout << "New matrix is created" << std::endl;
}
Matrix::~Matrix() {
for(int i = 0; i < size; i++)
delete[] Matr[i];
delete[] Matr;
Matr = NULL;
std::cout << "Matrix is deleted" << std::endl;
}
Matrix Matrix::MultipliedByMatrix(Matrix OtherMatr) {
Matrix new_matr = Matrix(this->GetSize());
int new_value;
for(int i = 0 ; i < size; i++)
for(int j = 0; j < size; j++) {
new_value = 0;
new_value += Matr[j][i] * OtherMatr.GetValue(i, j);
new_matr.SetValue(i, j, new_value);
}
return new_matr;
}
int Matrix::GetSize() {
return size;
}
int Matrix::GetValue(int i, int j) {
return Matr[i][j];
}
void Matrix::SetValue(int i, int j, int value) {
Matr[i][j] = value;
}
Did you write the Matrix class yourself? If so, I bet the problem is that you don't have a copy or move constructor. If so, the compiler will have generated one for you. This will copy the values of size and Matr but it won't create copies of the pointed-to arrays. When you write:
return new_matr;
this creates a new matrix (using the copy constructor - which just copies the pointer), and then calls the destructor of new_matr (which deletes the memory which is pointed to). The calling function is then dealing with junk memory, and when it tries to eventually delete the result, all hell will break loose
You also will need to write a move assignment operator.
Alternatively make Matr a std::vector<int> (of length 'size' squared), and write:
int Matrix::GetValue(int i, int j) {
return Matr[i*size+j];
}
(and similarly for other functions). std::vector has a proper copy and move constructor, and proper assignment behaviour - so it will all just work. (It will also be a lot faster - you save a whole pointer indirection.)
This is not an analytical answer to the question but a piece of advice with respect to solving (or better circumventing) the problem.
Avoid memory handling on your own if you can. (And it is very likely that you actually can avoid it.)
You can read my answer on the question "1D or 2D array, what's faster?" to get a lengthy explenation why it is probably undesirable to use the kind of memory layout you're using.
Furthermore, you'll find an (yet untested) example of how to implement a simple matrix container on top of std::vector.
You can look at the scheme and try to implement your own if you want. The design has several advantages compared to your implementation:
It is templated and thus usable with int as well as many other types.
Conformance to the standard container concept is achieved easily.
No destructor / copy constructor / move constructor or assignment operators required: std::vector is handling the resources and does the "dirty work" for you.
If you still want to use your RAW-Pointer approach (for academic purposes or something):
Read What is meant by Resource Acquisition is Initialization (RAII)? and try to understand the answers.
Read What is The Rule of Three? properly and make sure you have implemented (preferably obeying the RAII concept) those functions:
copy constructor,
destructor,
assignment operator and if desired
move constructor and
move assignment operator.
Still read my answer to the "1D or 2D array, what's faster?" question to see how you would want to organize your allocations in order to be exception safe in case of std::bad_alloc.
Example: Your constructor the 'a little better' way:
Matrix::Matrix(std::size_t const matr_size) // you have a size here, no sign required
{
Matr = new int*[matr_size];
std::size_t allocs(0U);
try
{ // try block doing further allocations
for (std::size_t i = 0; i < matr_size; ++i)
{
Matr[i] = new int[matr_size]; // allocate
++allocs; // advance counter if no exception occured
for(std::size_t j = 0; j < matr_size; j++)
{
Matr[i][j] = rand() % 100;
}
}
}
catch (std::bad_alloc & be)
{ // if an exception occurs we need to free out memory
for (size_t i = 0; i < allocs; ++i) delete[] Matr[i]; // free all alloced rows
delete[] Matr; // free Matr
throw; // rethrow bad_alloc
}
}
CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;
Constructor
This is how I'm allocating it:
char **board = new char*[width];
for(i = 0; i < width; i++){
board[i] = new char[height];
for(j = 0; j < height; j++)
board[i][j] = 0;
}
this->board = &board;
Inside the class, it's:
char ***board;
Destructor:
Now I want to delete it, so I wrote this (the board it the class field):
for(i = 0; i < width; i++)
delete (*board)[i];
delete (*board);
When running this:
Board* b = new Board(16, 30, 99);
delete b;
I get an Unhandled exception. Why?
You are storing a pointer to a variable on the stack, which becomes invalid as soon as the constructor returns. You should declare your class's data member as char **board and assign this->board = board.
EDIT: See also #Kerrek SB's comment. The local variable is redundant. Just use the data member directly (without the this->).
EDIT 2: Rectangular arrays are best created as a single array, using pointer arithmetic to index (which is what the compiler does with declared 2D arrays anyway):
char *board;
...
board = new char[width*height];
for(i = 0; i < width*height; ++i){
board[i] = 0;
}
...
char& operator()(int i, int j) { return board[width*i + j]; }
This has the advantage of requiring just one memory allocation (and therefore one delete[]). It also improves cache locality because the cells are contiguous.
Even better, if you know the dimensions at compile-time, use templates:
template <int W, int H>
class Board {
char board[W][H];
...
};
...
Board<8, 8>* b = new Board<8, 8>(...);
This requires no memory allocation at all (other than the new Board, of course).
Anything that you new you need to delete, in the exact same way:
board = new char*[width];
...
board[i] = new char[height];
...
...
delete[] board[i];
delete[] board;
No dereferencing is needed in this case.
You should use the powers of C++.
class Board
{
std::vector<std::vector<char>> board;
public:
Board(std::vector<std::vector<char>> const& board) : board(board) {}
Board(size_t x, size_t y, char val = 0)
{
std::vector<char> x2(x, val);
this->board(y, x2);
}
};
All you've got to do now is board[y].push_back(char_x_val) in order to append a new element to the end. You can treat board[y][x] just like any other 2D array (well, almost), but not worry about the deallocation.
Read up more on vectors here. (Anyone know a good tutorial?)