Dweeberly
Dweeberly

Reputation: 4777

Confused about move semantics w/ operator overloading

I'm confused about C++ move semantics when used with operator overloading.

For example: (header)

#pragma once
#include <vector>
namespace Mat {
    using namespace std;
    template <class T = double>
    class Matrix {
        public: 
        vector<vector<T>> &data;
        size_t Rows;
        size_t Cols;
        // ctor
        Matrix(size_t rows = 1, size_t cols = 1) :
            data(*(new vector<vector<T>>(rows, vector<T>(cols)))) {
            Rows = rows;
            Cols = cols;
            }
        // copy assignment
        Matrix &operator=(const Matrix &m) {
            cout << "Copy =" << endl;
            delete &data;
            Rows = m.Rows;
            Cols = m.Cols;
            data = *(new vector<vector<T>>(m.data));
            return *this;
            }
        // move assignment
        Matrix &operator=(Matrix &&m) {
            cout << "Move =" << endl;
            Rows = m.Rows;
            Cols = m.Cols;
            data = m.data;
            return *this;
            }
        // destructor
        ~Matrix() {
            delete &data;
            }
        // addition
        Matrix &operator+(const Matrix &right) {
            const auto &left = *this;
            auto &result = *(new Matrix<T>(left.Rows, left.Cols));
            for (size_t r = 0; r < Rows; r++) {
                for (size_t c = 0; c < Cols; c++) {
                    result.data[r][c] = left.data[r][c] + right.data[r][c];
                    }
                }
            return result;
            }
        };
    }

(main/driver)

int _tmain(int argc, _TCHAR* argv []) {
    Mat::Matrix<double> mat1(3,3);
    Mat::Matrix<double> mat2(3, 3);
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(1, 6);
    for (int r = 0; r < 3; r++) {
        for (int c = 0; c < 3; c++) {
            mat1.data[r][c] = distribution(generator);
            mat2.data[r][c] = distribution(generator);
            }
        }
    Mat::Matrix<double> mat3;
    mat3 = mat1 + mat2;
    }

When I execute this code. It indicates that "mat3 = mat1 + mat2" is using the copy assignment operator. I expected (and wanted) it to use the move assignment operator. I'm using VS2013.

Can someone explain why this is happening and how I can get the desired move semantics? Thanks

Upvotes: 1

Views: 90

Answers (2)

Shoe
Shoe

Reputation: 76240

Your operator+ not only is leaking memory, but is also returning a Mat::Matrix by reference. Therefore the expression mat1 + mat2 can only bind to:

Matrix &operator=(const Matrix&);

What you want to do is to return a Matrix by value, instead. Finally, I see you are using new all over the place. You don't need dynamic allocation, especially with std::vector.

Upvotes: 1

Jason
Jason

Reputation: 32490

Among a bunch of other issues, your operator+() is returning a non-const l-value reference, not a temporary r-value ... thus it's going to bind to the const l-value reference in the copy assignment operator.

Upvotes: 0

Related Questions