簡體   English   中英

如何改善矩陣的“ =”運算符重載?

[英]How to improve “=” operator overload for matrices?

我為帶有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()]();

讓我煩惱的是,我必須在賦值函數(以及其他一些函數!)中復制構造函數和析構函數的代碼,以使其正常工作。 有更好的書寫方式嗎?

理想的改進是Matrix& Matrix::operator=(const Matrix&) = default;

如果切換到使用std::vector進行矩陣存儲,則根本不需要實現復制/移動構造函數/賦值和析構函數。

如果您正在做的是編程練習,請創建自己的動態數組,並將其用於矩陣的實現中。

我不能推薦觀看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;
};

賦值運算符的規范實現利用了現有功能(復制/移動ctor,dtor和swap() ;請注意,使用非專用的std::swap()會很不好)。 看起來像這樣:

T& T::operator= (T val) {
    val.swap(*this);
    return *this;
}

很好地避免了重新實現現有的邏輯。 它還可以很好地處理自我分配問題,這在您的原始代碼中是個問題(它可以正常工作,但自我分配通常並不常見;通過檢查自我分配來對其進行優化通常會悲觀代碼)。

該參數按值傳遞以利用復制省略。

下面是使用此方法的主要注意事項。 總的來說,我更喜歡規范的實現,因為它通常更正確,而且所概述的問題通常並不那么相關(例如,無論何時剛創建對象時,傳輸的內存實際上都是“熱”的)。

  1. 它不會嘗試重用已分配且可能“熱”的內存。 相反,它總是使用新的內存。
  2. 如果保留的數據量很大,則有一些臨時保留的副本可能會超過系統限制。 首先重用現有內存和/或釋放內存都可以解決此問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM