I am new to C++11 and found move semantics and copy ellision are really great to write elegant and efficient code. However I have some problems would like to ask. Here I write a template class matrix.hpp
and use it to test behaviors of move semantics.
#include <vector>
#include <iostream>
using namespace std;
template<class T> class matrix {
public:
matrix(); // default constructor
matrix(const matrix<T>& mx); // copy constructor
matrix(matrix<T>&& mx); // move constructor
matrix(int rows_, int cols_);
matrix<T>& operator= (matrix<T>&& mx); // move assignment
matrix<T>& operator= (const matrix<T>& mx); // copy constructor
matrix<T> mean(int axis) const;
private:
int rows, cols;
std::vector<T> data;
};
template<class T> matrix<T>::matrix(): rows(0), cols(0), data(0) {}
template<class T> matrix<T>::matrix (int rows_, int cols_)
: rows(rows_), cols(cols_), data(rows * cols) {}
template<class T> matrix<T>::matrix(const matrix<T>& mx) {
cout << "copy-tor" << endl;
rows = mx.rows;
cols = mx.cols;
data = mx.data;
}
template<class T> matrix<T>::matrix(matrix<T>&& mx) {
cout << "move-tor" << endl;
rows = mx.rows;
cols = mx.cols;
data = std::move(mx.data);
}
template<class T> matrix<T>& matrix<T>::operator= (const matrix<T>& mx) {
cout << "copy-assign" << endl;
if (this != &mx) {
data.clear();
cols = mx.cols;
rows = mx.rows;
data = mx.data;
}
return *this;
}
template<class T> matrix<T>& matrix<T>::operator= (matrix<T>&& mx) {
cout << "move-assign" << endl;
if (this != &mx) {
data.clear();
rows = mx.rows;
cols = mx.cols;
data = std::move(mx.data);
}
return *this;
}
template<class T> matrix<T> matrix<T>::mean(int axis) const {
if (axis == 1) {
matrix<T> mx(1, cols);
// HERE compute mean vector ...
return mx;
} else if (axis == 0) {
matrix<T> mx(rows, 1);
// HERE compute mean vector ...
return mx;
}
}
And in the test.cpp
I test how copy constructors and move semantics are implemented in the following cases:
#include "matrix.hpp"
matrix<float> f() {
matrix<float> a(1,2);
return a;
}
matrix<float> g() {
matrix<float> *b = new matrix<float>(1,2);
return *b;
}
int main() {
matrix<float> a;
a = f(); // (*)
cout << "--" << endl;
a = g(); // (**)
cout << "--" << endl;
a = a.mean(1); // (***)
}
The result is:
move-assign
--
copy-tor
move-assign
--
move-tor
move-assign
The first result is straightforwardly inferred from the definition of move assigment. My guess for the second result is that the compiler will create a temporary of the object *b, and then std::move() this temporary object to a. For the third result it a bit strange. However if I initialize the local object mx
in the function's scope mean(int axis)
then there is just one move-assign
. Could anyone explain it to me? Thanks!
EDIT I just edited the mean(int axis)
just as it is in my code.