I wrote my own Matrix class. To test its constructors and operators, I need to call each one. How can i do this? Now called move operator and copy constructor, but still need move constructor and assignment operator
Matrix(const Matrix &other) : data(new T[other.rows * other.cols]), rows(other.rows), cols(other.cols)
{
std::cout << "copy constructor" << std::endl;
for (size_t i = 0; i < rows * cols; i)
{
data[i] = other.data[i];
}
}
Matrix &operator=(const Matrix<T> &other)
{
std::cout << "assignment operator" << std::endl;
if (&other == this)
{
return *this;
}
if (rows != other.rows || cols != other.cols)
{
throw std::logic_error("Error assigning matrices of different sizes");
}
data = (static_cast<T *>(operator new[](sizeof(T) * rows * cols, static_cast<std::align_val_t>(alignof(T)))));
rows = other.rows;
cols = other.cols;
for (size_t i = 0; i < rows * cols; i)
{
data[i] = other.data[i];
}
return *this;
}
Matrix(Matrix &&other) noexcept : data(other.data), rows(other.rows), cols(other.cols)
{
std::cout << "Move constructor" << std::endl;
other.data = nullptr;
other.rows = 0;
other.cols = 0;
}
Matrix &operator=(Matrix<T> &&other)
{
std::cout << "move operator" << std::endl;
if (&other == this)
{
return *this;
}
if (rows != other.rows || cols != other.cols)
{
throw std::logic_error("Error assigning matrices of different sizes");
}
clean();
std::swap(data, other.data);
std::swap(rows, other.rows);
std::swap(cols, other.cols);
other.data = nullptr;
other.rows = 0;
other.cols = 0;
return *this;
}
Here are the constructor calls, how to call all the available constructors in general? main.cpp
Matrix<int> mat1(3, 3);
Matrix<int> mat2(3, 3);
mat1.fillMatrix();
mat2.fillMatrix();
mat2 = std::move(mat1);
Matrix<int> mat3 = mat1;
mat3.printMatrix();
Matrix<int> mat4(mat1);
CodePudding user response:
You can use casts and std::move
here:
Matrix<int> source;
Matrix<int> target(std::move(source)); // move constructor
Matrix<int> source;
Matrix<int> target;
target = std::move(source); // move assignment operator
Matrix<int> source;
Matrix<int> target(static_cast<Matrix<int> const&>(source)); // copy constructor
Matrix<int> source;
Matrix<int> target;
target = static_cast<Matrix<int> const&>(source); // copy assignment
Note that technically the casts to const references are unnecessary, but with the cast you would also be able to prevent another overload taking Matrix<int>&
as parameter from being applicable.
Note: If you write unit tests, it may be a good idea to add static_assert
s checking for the existance of the special member functions.
static_assert(std::is_move_constructible_v<Matrix<int>>, "Matrix<int> is not move constructible");
static_assert(std::is_move_assignable_v<Matrix<int>>, "Matrix<int> is not move assignable");
static_assert(std::is_copy_constructible_v<Matrix<int>>, "Matrix<int> is not copy constructible");
static_assert(std::is_copy_assignable_v<Matrix<int>>, "Matrix<int> is not copy assignable");
This way you'd get a compiler error, if you got one of the signatures wrong...
CodePudding user response:
Matrix<int> mat1(3, 3); // not shown constructor
Matrix<int> mat2(mat1); // copy constructor
Matrix<int> mat3 = mat1; // copy constructor
mat3 = mat1; // operator=(const Matrix&)
Matrix<int> mat4(std::move(Matrix<int>(3, 3))); // move constructor
Matrix<int> mat5 = std::move(Matrix<int>(3, 3)); // move constructor
mat5 = Matrix<int>(3, 3); // operator=(Matrix&&)
https://godbolt.org/z/eoodeoK6h
Explicit std::move
is used for avoiding elisions.
CodePudding user response:
Copy and move constructors are called when you initializing new object. Difference between move and copy is what argument you use to initialize it. If it tempory or special std::move function is used than move ctor would be called(not in all cases though), otherwise copy constructor. For example:
Matrix<int> mat1(3,3);
Matrix<int> mat3 = mat1; //cp-ctor
Matrix<int> mat4 = std::move(mat1);//mv-ctor
Matrix<int> mat5(mat1);//cp-ctor full equivalent of second line
Matrix<int> mat6 = someFunctionReturningMatrixByCopy(); //mv-ctor