Я новичок в создании собственных шаблонных классов на C ++ и после нескольких часов поиска в Интернете ответов и игры с функцией & его параметры я сдал. У меня проблемы во время выполнения с оператором следующего класса «=»:
В matrix.h:
template <class datatype> class Matrix{
datatype** element;
unsigned int m,n;
public:
Matrix(unsigned int M, unsigned int N,datatype x){
m=M; // # of rows
n=N; // # of cols
element=new datatype*[m];
for(int i=0;i<m;i++) element[i]=new datatype[n];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
element[i][j]=x;
}
void print(){
for(int i=0;i<m;i++){
for(int j=0;j<n;j++) cout<<element[i][j]<<" ";
cout<<"\n";
}
}
Matrix operator=(Matrix A){
for(int i=0;i<m;i++) delete[] element[i];
delete[] element;
m=A.m;
n=A.n;
element=new datatype*[m];
for(int i=0;i<m;i++) element[i]=new datatype[n];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
element[i][j]=A.element[i][j];
return *this;
}
};
Когда я иду, чтобы проверить это, сборник & ссылки запускаются без ошибок, и я получаю совершенно корректный отпечаток. Но при попытке присвоить одну матрицу значению другой, программа вылетает с сообщением «matrix_test перестал работать». Вот мой тестовый код в matrix_test.cpp:
Matrix<int> M(5u,3u,0);
Matrix<int> P(2u,7u,3);
int main(){
M.print();
cout<<"\n";
P.print();
cout<<"\n";
P=M;
P.print();
}
Заранее спасибо за помощь!
Во-первых, реализация вашего копирования-задания имеет довольно фундаментальные недостатки: когда вы delete[]
представление, а затем выделить новую копию, распределение может выбросить, в этом случае ваша исходная матрица delete[]
г и не может быть восстановлено. Таким образом, присвоение не является безопасным для исключения.
Наилучшая реализация оператора копирования-копирования — это использование конструкции копирования и swap()
член. Конечно, оба этих члена отсутствуют в вашем классе, но давайте вернемся к этому позже:
Matrix& Matrix::operator= (Matrix other) {
other.swap(*this);
return *this;
}
При передаче аргумента по значению он фактически копируется. Чтобы скопировать объект, вам понадобится конструктор копирования. В общем, если вам нужно назначение копирования, вам обычно также нужен конструктор копирования и деструктор (бывают случаи, когда вам нужно только назначение копирования, чтобы сделать назначение копирования строго исключительным, но это другое обсуждение).
Целью конструктора копирования является копирование другого объекта, например, когда объект передается по значению:
Matrix::Matrix(Matrix const& other)
: element(new datatype*[other.m])
, m(other.m)
, n(other.n)
{
int count(0);
try {
for (; count != m; ++count) {
this->element[count] = new datatype[m];
std::copy(other.element[count], other.element[count] + m,
this->element[count]);
}
}
catch (...) {
while (count--) {
delete[] this->element[count];
}
delete[] this->element;
throw;
}
}
Я не уверен, что восстановление из исключения действительно правильно: я не могу справиться со сложностью справиться со всеми этими указателями! В моем коде я бы позаботился о том, чтобы все ресурсы немедленно создавали объект, предназначенный для их автоматического освобождения, но это потребовало бы изменения типа объектов. Учитывая определение типа, также необходим деструктор:
Matrix::~Matrix() {
for (int count(this->m); count--; ) {
delete[] this->element[count];
}
delete[] this->element;
}
Наконец, для более крупных объектов swap()
член часто удобен. Цель swap()
это просто обменять содержимое двух объектов. Способ реализовать это сделать для каждого члена std::swap()
:
void Matrix::swap(Matrix& other) {
using std::swap;
swap(this->element, other.element);
swap(this->n, other.n);
swap(this->m, other.m);
}
Учитывая, что все члены этого класса являются встроенными типами (хотя они, вероятно, не должны быть), using
Танец на самом деле не нужен. Однако при наличии специализированных перегрузок swap()
в других пространствах имен, чем std::swap()
для пользовательских типов вышеупомянутый подход гарантирует, что они найдены путем зависимого поиска аргумента.
Других решений пока нет …