Страница 1 из 1

Шаблон матрици

Добавлено: 29 июн 2016, 09:05
Kazanove

Код: Выделить всё

 
#include <iostream>
#include <ctime>

template <typename T>
class Matrix {
	int Size;
	T** matrix;
	void Create(int);
	void Delete();
public:
	Matrix();
	Matrix(int);
	~Matrix();
	void FillAuto();
	void Print();
	Matrix operator+(const Matrix &) const;
	Matrix operator-(const Matrix &) const;
	Matrix operator*(const Matrix &) const;
	Matrix operator/(const Matrix &) const;
	T Min();
	T Max();
};

int main() {
	srand((size_t)time(nullptr));
	Matrix<int> MI;
	Matrix<int> MI1;
	Matrix<int> MI2;
	MI.FillAuto();
	MI1.FillAuto();
	MI.Print();
	MI1.Print();
	MI2 = MI + MI1;
	MI2.Print();
	MI2 = MI - MI1;
	MI2.Print();
	MI2 = MI * MI1;
	MI2.Print();
	std::cout << MI2.Max() << "\n";
	std::cout << MI2.Min() << "\n";
	return 0;
}

template<typename T>
Matrix<T>::Matrix() {
	this->Size = 3;
	this->matrix = NULL;
	this->Create(this->Size);

}

template<typename T>
Matrix<T>::Matrix(int Size) {
	this->Size = Size;
	this->matrix = NULL;
	this->Create(this->Size);
}

template<typename T>
Matrix<T>::~Matrix() {
	this->Delete();
}

template<typename T>
void Matrix<T>::FillAuto() {
	for (int i = 0;i < this->Size;i++) {
		for (int j = 0;j < this->Size;j++) {
			this->matrix[i][j] = rand() % 10;
		}
	}
}

template<typename T>
void Matrix<T>::Print() {
	for (int i = 0; i < this->Size; i++) {
		for (int j = 0;j < this->Size;j++) {
			std::cout << this->matrix[i][j] << " ";
		}
		std::cout << "\n";
	}
	std::cout << "\n\n";
}

template<typename T>
Matrix<T> Matrix<T>: :o perator+(const Matrix &Obj) const {
	if (this->Size == Obj.Size) {
		Matrix<T>Result;
		for (int i = 0;i < this->Size;i++) {
			for (int j = 0;j < this->Size;j++) {
				Result.matrix[i][j] = this->matrix[i][j] + Obj.matrix[i][j];
			}
		}
		return Result;
	}
	else {
		std::cerr << "ERROR!!!\n";
		exit(1);
	}
}

template<typename T>
Matrix<T> Matrix<T>: :o perator-(const Matrix &Obj) const {
	if (this->Size == Obj.Size) {
		Matrix<T>Result;
		for (int i = 0;i < this->Size;i++) {
			for (int j = 0;j < this->Size;j++) {
				Result.matrix[i][j] = this->matrix[i][j] - Obj.matrix[i][j];
			}
		}
		return Result;
	}
	else {
		std::cerr << "ERROR!!!\n";
		exit(1);
	}
}

template<typename T>
Matrix<T> Matrix<T>: :o perator*(const Matrix &Obj) const {
	if (this->Size == Obj.Size) {
		Matrix<T> Result(this->Size);
		for (int i = 0;i < this->Size;i++) {
			for (int j = 0;j < this->Size;j++) {
				for (int k = 0; k < this->Size; k++) {
					Result.matrix[i][j] += this->matrix[i][k] * Obj.matrix[k][j];
				}
			}
		}
		return Result;
	}
	else {
		std::cerr << "ERROR!!!\n";
		exit(1);
	}
}

template<typename T>
Matrix<T> Matrix<T>: :o perator/(const Matrix &) const {
	std::cerr << "Error!!! The division of matrix-matrix can not be";
	exit(1);
}

template<typename T>
T Matrix<T>::Min() {
	T Result = this->matrix[0][0];
	for (int i = 0; i < this->Size;i++) {
		for (int j = 0; j < this->Size;j++) {
			if (Result > this->matrix[i][j]) {
				Result = this->matrix[i][j];
			}
		}
	}
	return Result;
}

template<typename T>
T Matrix<T>::Max() {
	T Result = this->matrix[0][0];
	for (int i = 0; i < this->Size;i++) {
		for (int j = 0; j < this->Size;j++) {
			if (Result < this->matrix[i][j]) {
				Result = this->matrix[i][j];
			}
		}
	}
	return Result;
}
template<typename T>
void Matrix<T>::Create(int Size) {
	if (Size > 1) {
		this->Delete();
		this->matrix = new T*[Size];
		for (int i = 0;i < Size;i++) {
			this->matrix[i] = new T[Size];
			for (int j = 0;j < Size;j++) {
				this->matrix[i][j] = 0;
			}
		}
	}
}

template<typename T>
void Matrix<T>: :D elete() {
	if (this->matrix != NULL) {
		for (int i = 0;i < Size;i++) {
			delete[] this->matrix[i];
		}
		delete[] this->matrix;
	}
}

а теперь вопрос
при вызове деструктора (а точнее метода Delete) выдает ошибку при освобождении памяти

Re: Шаблон матрици

Добавлено: 01 июл 2016, 13:51
Romeo
Дело в том, что вот в этой строке:

Код: Выделить всё

MI2 = MI + MI1;
Выполняются на самом деле следующие вызовы:

Код: Выделить всё

Matrix<int> temp(  MI.operator+(MI1) );
MI2.operator=(temp);
temp.~Matrix<int>();
То есть, иными словами, создаётся временный объект, затем MI2 присваивается временный объект, и в конце временный объект удаляется.

Так как оператор присваивания у тебя не определён, то компилятор генерирует дефолтный оператор присваивания, который просто вызывает операторы присваивания для всего членов класса. Замечу, что оператор присваивания для обычного указателя просто копирует адрес этого указателя. Отсюда мы имеем неприятное последствие: внутренний указатель matrix удаляется сначала в момент удаления временного объекта, а потом мы тот же самый указатель (ведь адрес был скопирован), пытаемся удалить, когда заканчивается время жизни переменной MI2.

Исправить указанную ситуацию можно переопределив оператор присваивания и конструктор копирования, и запрограммировать в них не глупое поверхностное копирование адресов, а полное глубокое копирование (выделение новой памяти под matrix и копирование поэлементно). Для этих двух способов копирования данных в C++ даже есть специальные термины shallow copy и deep copy соответственно. Очень рекомендую почитать о них в интернетах. Так же рекомендую прочитать мою тему с задачкой на deep copy на нашем форуме.