我为具有2D数组的类重载了赋值运算符,但是为了进行内存管理和调整大小,我必须首先删除先前的矩阵,然后构造一个新的矩阵,然后才能开始赋值。
Matrix& Matrix::operator = (const Matrix& m1){
for (int i = 0; i < m_rows; ++i)
delete[] m_matrix[i];
delete[] m_matrix;
m_matrix = new double*[m1.rows()];
for (int i = 0; i < m1.rows(); ++i)
m_matrix[i] = new double[m1.cols()]();
for (int k = 0; k < m1.rows(); ++k)
for (int j = 0; j < m1.cols(); ++j)
m_matrix[k][j] = m1.m_matrix[k][j];
m_rows = m1.rows();
m_cols = m1.cols();
return *this;
}
实际上,这部分是我班级的析构函数:
for (int i = 0; i < m_rows; ++i)
delete[] m_matrix[i];
delete[] m_matrix;
这部分类似于构造函数:
m_matrix = new double*[m1.rows()];
for (int i = 0; i < m_rows; ++i)
m_matrix[i] = new double[m1.cols()]();
让我烦恼的是我必须复制构造函数&#39;和析构者&#39;赋值函数中的代码(以及其他一些函数!)使其正常工作。有没有更好的方法来写它?
答案 0 :(得分:3)
理想的改进是Matrix& Matrix::operator=(const Matrix&) = default;
。
如果切换到使用std::vector
进行矩阵存储,则根本不需要实现复制/移动构造函数/赋值和析构函数。
如果您正在进行的是编程练习,请创建自己的动态数组并在矩阵的实现中使用它。
我不能建议观看Better Code: Runtime Polymorphism by Sean Parent,他有效地演示了为什么你应该努力编写不需要复制/移动构造函数/赋值和析构函数的非默认实现的类。
示例:
template<class T>
class Matrix
{
std::vector<T> storage_;
unsigned cols_ = 0;
public:
Matrix(unsigned rows, unsigned cols)
: storage_(rows * cols)
, cols_(cols)
{}
// Because of the user-defined constructor above
// the default constructor must be provided.
// The default implementation is sufficient.
Matrix() = default;
unsigned columns() const { return cols_; }
unsigned rows() const { return storage_.size() / cols_; }
// Using operator() for indexing because [] can only take one argument.
T& operator()(unsigned row, unsigned col) { return storage_[row * cols_ + col]; }
T const& operator()(unsigned row, unsigned col) const { return storage_[row * cols_ + col]; }
// Canonical swap member function.
void swap(Matrix& b) {
using std::swap;
swap(storage_, b.storage_);
swap(cols_, b.cols_);
}
// Canonical swap function. Friend name injection.
friend void swap(Matrix& a, Matrix& b) { a.swap(b); }
// This is what the compiler does for you,
// not necessary to declare these at all.
Matrix(Matrix const&) = default;
Matrix(Matrix&&) = default;
Matrix& operator=(Matrix const&) = default;
Matrix& operator=(Matrix&&) = default;
~Matrix() = default;
};
答案 1 :(得分:1)
赋值运算符的规范实现利用现有功能(复制/移动ctor,dtor和swap()
;请注意,使用非专用std::swap()
会很糟糕。它看起来像这样:
T& T::operator= (T val) {
val.swap(*this);
return *this;
}
很好地避免重新实现其他现有逻辑。它还优雅地处理自我分配,这是原始代码中的一个问题(它会起作用,但自我分配通常相当罕见;通过检查自我分配来优化它通常会使代码失望)。
参数通过值传递以利用复制省略。
这种方法的主要警告如下。一般来说,我更喜欢规范实现,因为它通常更正确,并且概述的问题通常不是那么相关(例如,当对象刚刚创建时,转移的内存实际上是#34;热&#34;)。